(五)菜单、图像、相机模块

1.菜单模块

1.1 建包

  • view
 xmlns:prism="http://prismlibrary.com/"
 xmlns:share="clr-namespace:Company.Application.Share.Prism;assembly=Company.Application.Share"
 prism:ViewModelLocator.AutoWireViewModel="True"
  • view model
  • applicationMenuModule配置类

1.2 下载包

image

1.3 添加引用

image

1.4 配置类

  • 使用coremodule的方法
    image
    因为在菜单模块可能有一些业务类型需要在项目初始化时就加到容器里面

  • 要求是在加载主模块main的时候同时把菜单模块加载
    给菜单配置类和主模块配置类添加按需加载
    image
    主模块添加模块依赖,加载主模块时也加载菜单栏
    image

  • 在入口程序的load事件中,登陆验证通过的回调函数,加载主模块,同时加载了菜单栏
    image

1.5.模块的加载

参考第一章的两种方法,用第二种方式的时候
要先生成release版本,然后生成debug版本再运行。

2.图像模块

2.1 创建模块的步骤同1中菜单模块

2.2 页面

大致写结构:
image

2.3 加载模块

在main模块加载时同时加载,添加模块依赖
image

此时主模块的这两个部分已经有了大致设计
image

3.相机模块

类库

  • 首先创建相机的接口,确定相机有哪些业务逻辑
    image
  • 相机配置类,因为不同相机有不同的参数,初始化传入相机参数
    image
  • 抽象类相机,对接口进行简单实现,然后子类在针对不同相机进行不同的实现抽象方法。(多态)

做个修改,action的泛型类型改为Photo

 public abstract class CameraBase : ICamera
 {
     public CameraConfig CameraConfig { get; private set; }
     public bool Initialized { get; private set; }
     //当回传了图片要做的事情
     public event Action<Photo> OnGrabbed;

     public void Close()
     {
         if (Initialized)
         {
             DoClose();//关闭的方法不在这里写,在子类中需要完成相应的业务
             Initialized = false;
         }
     }

     public bool Init(CameraConfig cameraConfig)
     {
         //不同的相机分辨率不一样,所以针对不同的相机要有不同参数配置---》新建配置类
         CameraConfig=cameraConfig;
         if (Initialized)
         {
             throw new Exception("相机重复初始化");
         }
         if (DoInit())
         {
             Initialized = true;
             return true;
         }
         return false;
     }

     protected void InvokeOnGrabbed(Photo image)
     {
         //表示事件未被订阅
         if (OnGrabbed == null) return;
         //如果订阅可能订阅多个
         foreach(Action<Photo> item in OnGrabbed.GetInvocationList())
         {
             item.Invoke(image);
         }
     }
     //抽象方法,由子类实现
     public abstract void DoClose();
     public abstract bool DoInit();
     public abstract bool Trigger();
 }

3.1 知识点补充

IntPtr介绍
GetInvocationList
invoke和begininvoke 区别

4.非托管内存数组的管理

4.1 内存帮助

写在helper中
RtlCopyMemory与RtlMoveMemory
三种函数的使用
内存复制,填入,清零的函数声明写法

 public  class MemoryHelper
 {
     /// <summary>
     /// 内存清零
     /// </summary>
     /// <param name="intPtr"></param>
     /// <param name="size"></param>
     [DllImport("kernel32.dll",EntryPoint = "RtZeroMemory",CharSet =CharSet.Ansi)]
     public static extern void ZeroMemory(IntPtr intPtr, long size);
     /// <summary>
     /// 内存复制
     /// </summary>
     /// <param name="dest"></param>
     /// <param name="src"></param>
     /// <param name="length"></param>
     [DllImport("kernel32.dll", EntryPoint = "RtMoveMemory", CharSet = CharSet.Ansi)]
     public static extern void CopyMemory(IntPtr dest, IntPtr src, long length);

     /// <summary>
     /// 将指定值填入内存
     /// </summary>
     /// <param name="dest"></param>
     /// <param name="src"></param>
     /// <param name="length"></param>
     [DllImport("kernel32.dll", EntryPoint = "RtFillMemory", CharSet = CharSet.Ansi)]
     public static extern void FillMemory(IntPtr dest, long length,byte value);
 }

4.2 非托管数据基类

  1. 在core新建model包
  2. IDisposable提供一种用于释放非托管资源的机制。
  3. UnmanagedArrayBase抽象类实现IDisposable接口
  4. Marshal.AllocHGlobal
    通过使用指定的字节数,从进程的非托管内存中分配内存。
  5. C#中的析构函数
  6. C#【必备技能篇】Marshal是什么?怎么用?
  7. C#的DllImport使用方法详解
  8. Bitmap 类
  9. Bitmap 类官网
  public abstract class UnmanagedArrayBase : IDisposable
  {
      /// <summary>
      /// 图像数据的指针(相机传来的数据都是以指针的形式)
      /// </summary>
      public IntPtr Header { get; private set; }
      /// <summary>
      /// 元素的数量
      /// </summary>
      public long Count { get; }

      /// <summary>
      /// 单个元素的字节数长度
      /// </summary>
      private readonly int Size;
      public long Length => Count * Size;//总长度

      //isResetMemory申请这个内存后是否默认把这片内存全部清0
      protected UnmanagedArrayBase(long count,int size,bool isResetMemory=true) 
      {
          if (count <= 0) throw new ArgumentException("count不能小于零");
          if (size <= 0) throw new ArgumentException("size不能小于零");
          
          Count = count;
          Size = size;
          Header=Marshal.AllocHGlobal(new IntPtr(Length));//指针长度等于相机数据大小的长度

          if(isResetMemory )
          {
              MemoryHelper.ZeroMemory(Header, Length);
          }
      }

      ~UnmanagedArrayBase()//析构函数,在对象被销毁时自动被调用
      {
          Dispose();
      }
      public void Dispose()
      {
          Dispose(true);
          GC.SuppressFinalize(this);//?
      }

      //已经释放的不可以重复释放
      protected bool disposed;
      protected void Dispose(bool disposing)
      {
          if (!disposed) return;
          if(disposing)
          {
              //todo 清理托管内存
          }
          if (Header != IntPtr.Zero)
          {
              Marshal.FreeHGlobal(Header);
              Header= IntPtr.Zero;//初始化为零
          }
          disposed = true;
      }
  }

4.3 子类

 public  class UnmanagedArray2D<T>:UnmanagedArrayBase where T : struct  
{
    public UnmanagedArray2D(int  width, int height, bool isResetMemory = true) : base(width*height, Marshal.SizeOf(typeof(T)), isResetMemory)
    {
        //base里面是给基类的
        //宽度高度给到自己的属性
        Width = width;
        Height = height;
    }

    public int Width { get; }
    public int Height { get; }
    public int Stride=> Width*Marshal.SizeOf(typeof(T));

    public UnmanagedArray2D<T> DeepClone()
    {
        var temp=new UnmanagedArray2D<T>(Width, Height);
        MemoryHelper.CopyMemory(temp.Header,this.Header,Length);
        return temp;
    }
}

4.4 BRAG图像结构体封装

有两种BGR三通道和 BGRA 四通道的
image
image

4.5 图像的封装

image

posted @ 2023-12-06 15:04  huihui不会写代码  阅读(68)  评论(0)    收藏  举报