1
0

2 Revīzijas 4da5098172 ... 4a00bdcadc

Autors SHA1 Ziņojums Datums
  向羽 孟 4a00bdcadc 合并master 6 dienas atpakaļ
  向羽 孟 9de730a006 20251115001 多线程管理程序加入,演示模板添加了相机识别的双线程控制以及通讯的单线程控制,优化了海康的相机类 6 dienas atpakaļ

+ 50 - 29
MvvmScaffoldFrame48.DLL/CameraTools/HikCamera.cs

@@ -18,7 +18,14 @@ namespace MvvmScaffoldFrame48.DLL.CameraTools
         /// <summary>
         /// 相机实例
         /// </summary>
-        private IDevice device;
+        private IDevice _device = null;
+        public IDevice Device
+        {
+            get
+            {
+                return _device;
+            }
+        }
         #endregion
 
         #region 变量
@@ -29,17 +36,31 @@ namespace MvvmScaffoldFrame48.DLL.CameraTools
         #endregion
 
         #region 构造函数
+        
+        public HikCamera()
+        {
+            if (_device != null && _device.IsConnected)
+            {
+                _device.Close();
+                _device.Dispose();
+            }
+        }
         /// <summary>
         /// 相机构造函数
         /// </summary>
         /// <param name="device">相机实例</param>
         public HikCamera(IDevice device)
         {
+            if (_device != null && _device.IsConnected)
+            {
+                _device.Close();
+                _device.Dispose();
+            }
             if (device == null)
             {
                 throw new Exception("相机实例不能为空");
             }
-            this.device = device;
+            this._device = device;
         }
 
         /// <summary>
@@ -48,22 +69,22 @@ namespace MvvmScaffoldFrame48.DLL.CameraTools
         /// <param name="deviceInfo">相机信息</param>
         public HikCamera(IDeviceInfo deviceInfo)
         {
-            if (device != null && device.IsConnected)
+            if (_device != null && _device.IsConnected)
             {
-                device.Close();
-                device.Dispose();
+                _device.Close();
+                _device.Dispose();
             }
             try
             {
                 // 打开设备
-                device = DeviceFactory.CreateDevice(deviceInfo);
+                _device = DeviceFactory.CreateDevice(deviceInfo);
             }
             catch (Exception ex)
             {
                 throw new Exception(ex.Message);
             }
 
-            int result = device.Open();
+            int result = _device.Open();
             if (result != MvError.MV_OK)
             {
                 throw new Exception("打开相机失败");
@@ -71,10 +92,10 @@ namespace MvvmScaffoldFrame48.DLL.CameraTools
 
 
             // 判断是否为gige设备
-            if (device is IGigEDevice)
+            if (_device is IGigEDevice)
             {
                 // 转换为gigE设备
-                IGigEDevice gigEDevice = device as IGigEDevice;
+                IGigEDevice gigEDevice = _device as IGigEDevice;
 
                 // 探测网络最佳包大小(只对GigE相机有效)
                 result = gigEDevice.GetOptimalPacketSize(out int optionPacketSize);
@@ -85,7 +106,7 @@ namespace MvvmScaffoldFrame48.DLL.CameraTools
                 }
                 else
                 {
-                    result = device.Parameters.SetIntValue("GevSCPSPacketSize", (long)optionPacketSize);
+                    result = _device.Parameters.SetIntValue("GevSCPSPacketSize", (long)optionPacketSize);
                     if (result != MvError.MV_OK)
                     {
                         //Log("Warning: Set Packet Size failed!", result);
@@ -104,15 +125,15 @@ namespace MvvmScaffoldFrame48.DLL.CameraTools
         public bool ReLoadCameraDevice(IDeviceInfo deviceInfo)
         {
             bool Blresult = false;
-            if (device != null && device.IsConnected)
+            if (_device != null && _device.IsConnected)
             {
-                device.Close();
-                device.Dispose();
+                _device.Close();
+                _device.Dispose();
             }
             try
             {
                 // 打开设备
-                device = DeviceFactory.CreateDevice(deviceInfo);
+                _device = DeviceFactory.CreateDevice(deviceInfo);
                 Blresult = true;
             }
             catch
@@ -120,7 +141,7 @@ namespace MvvmScaffoldFrame48.DLL.CameraTools
                 return Blresult;
             }
 
-            int result = device.Open();
+            int result = _device.Open();
             if (result != MvError.MV_OK)
             {
                 Blresult = false;
@@ -128,10 +149,10 @@ namespace MvvmScaffoldFrame48.DLL.CameraTools
             }
 
             // 判断是否为gige设备
-            if (device is IGigEDevice)
+            if (_device is IGigEDevice)
             {
                 // 转换为gigE设备
-                IGigEDevice gigEDevice = device as IGigEDevice;
+                IGigEDevice gigEDevice = _device as IGigEDevice;
 
                 // 探测网络最佳包大小(只对GigE相机有效)
                 result = gigEDevice.GetOptimalPacketSize(out int optionPacketSize);
@@ -141,7 +162,7 @@ namespace MvvmScaffoldFrame48.DLL.CameraTools
                 }
                 else
                 {
-                    result = device.Parameters.SetIntValue("GevSCPSPacketSize", (long)optionPacketSize);
+                    result = _device.Parameters.SetIntValue("GevSCPSPacketSize", (long)optionPacketSize);
                     if (result != MvError.MV_OK)
                     {
                         //Log("Warning: Set Packet Size failed!", result);
@@ -159,10 +180,10 @@ namespace MvvmScaffoldFrame48.DLL.CameraTools
             bool result = false;
             try
             {
-                if (device == null) return result;
-                device.StreamGrabber.SetImageNodeNum(30);
-                int ret = device.StreamGrabber.StartGrabbing();
-                if (ret != MvError.MV_OK)
+                if (_device == null) return result;
+                _device.StreamGrabber.SetImageNodeNum(30);
+                int ret = _device.StreamGrabber.StartGrabbing();
+                if (ret == MvError.MV_OK)
                 {
                     result = true;
                 }
@@ -182,9 +203,9 @@ namespace MvvmScaffoldFrame48.DLL.CameraTools
             bool result = false;
             try
             {
-                if (device == null) return result;
-                int ret = device.StreamGrabber.StopGrabbing();
-                if (ret != MvError.MV_OK)
+                if (_device == null) return result;
+                int ret = _device.StreamGrabber.StopGrabbing();
+                if (ret == MvError.MV_OK)
                 {
                     result = true;
                 }
@@ -204,7 +225,7 @@ namespace MvvmScaffoldFrame48.DLL.CameraTools
         public bool GetOnceImage(out IFrameOut IFrameData)
         {
             bool result = false;
-            int BRet = device.StreamGrabber.GetImageBuffer(1000, out IFrameData);
+            int BRet = _device.StreamGrabber.GetImageBuffer(1000, out IFrameData);
             if (BRet == 0 && IFrameData != null) result = true;
             else return result;
             if (lastframeNum == -1)
@@ -232,12 +253,12 @@ namespace MvvmScaffoldFrame48.DLL.CameraTools
         public CameraImageSizeCModel GetCamereImageSize()
         {
             CameraImageSizeCModel cameraImageSize = null;
-            if (device != null)
+            if (_device != null)
             {
                 try
                 {
-                    device.Parameters.GetIntValue("Width", out IIntValue PixWidth);
-                    device.Parameters.GetIntValue("Height", out IIntValue PixHeight);
+                    _device.Parameters.GetIntValue("Width", out IIntValue PixWidth);
+                    _device.Parameters.GetIntValue("Height", out IIntValue PixHeight);
                     cameraImageSize = new CameraImageSizeCModel()
                     {
                         Height = (int)PixHeight.CurValue,

+ 21 - 0
MvvmScaffoldFrame48.DLL/CameraTools/HikVision.cs

@@ -56,6 +56,27 @@ namespace MvvmScaffoldFrame48.DLL.CameraTools
             }
             return;
         }
+
+        /// <summary>
+        /// 获取相机列表
+        /// </summary>
+        /// <param name="CamList"></param>
+        /// <returns></returns>
+        public static void GetCameraList(out List<IDeviceInfo> CameraInfoList)
+        {
+            CamList = new List<IDeviceInfo>();
+            int nRet = DeviceEnumerator.EnumDevices(enumTLayerType, out CamList);
+            if (nRet != MvError.MV_OK)
+            {
+                CameraInfoList = null;
+                return;
+            }
+            else
+            {
+                CameraInfoList = CamList;
+            }
+            return;
+        }
         #endregion
     }
 }

+ 6 - 0
MvvmScaffoldFrame48.DLL/MvvmScaffoldFrame48.Dll.csproj

@@ -111,6 +111,11 @@
     <Compile Include="LogTools\TxtLog.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="SystemTools\SystemRunTimeTools.cs" />
+    <Compile Include="ThreadManager\CameraGroup.cs" />
+    <Compile Include="ThreadManager\CommunicationThread.cs" />
+    <Compile Include="ThreadManager\IImageProcessingAlgorithmHikVision.cs" />
+    <Compile Include="ThreadManager\ProcessingAlgorithm.cs" />
+    <Compile Include="ThreadManager\ThreadManager.cs" />
     <Compile Include="UserManager.cs" />
     <Compile Include="WindowsTools\OnScreenKeyboardTools.cs" />
     <Compile Include="WindowsTools\SystemMonitorClass.cs" />
@@ -144,5 +149,6 @@
       <Version>2.0.2</Version>
     </PackageReference>
   </ItemGroup>
+  <ItemGroup />
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
 </Project>

+ 233 - 0
MvvmScaffoldFrame48.DLL/ThreadManager/CameraGroup.cs

@@ -0,0 +1,233 @@
+using MvCameraControl;
+using MvvmScaffoldFrame48.DLL.CameraTools;
+using MvvmScaffoldFrame48.Model.ResultModel;
+using System;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace MvvmScaffoldFrame48.DLL.ThreadManager
+{
+    /// <summary>
+    /// 相机组配置和状态管理类
+    /// 管理单个相机的采集和处理线程及相关资源
+    /// </summary>
+    public class CameraGroup
+    {
+        public HikCamera Camera { get; set; }
+        public int CameraId { get; set; }
+        public bool IsRunning { get; set; }
+        public CancellationTokenSource CancellationTokenSource { get; set; }
+        public Task CameraTask { get; set; }
+        public Task ProcessingTask { get; set; }
+        public ConcurrentQueue<IImage> ImageQueue { get; set; }
+        public SemaphoreSlim QueueSemaphore { get; set; }
+
+        // 图像处理算法(接口方式)
+        public IImageProcessingAlgorithmHikVision ImageProcessor { get; set; }
+
+        // 结果发送事件,当图像处理完成时触发
+        public event EventHandler<CameraProcessEventArgsResultModel> ProcessResultAvailable;
+
+        /// <summary>
+        /// 发送处理结果到通信线程的方法
+        /// 多个线程可以共用此方法
+        /// </summary>
+        /// <param name="resultData">处理结果数据</param>
+        public void SendProcessResult(object resultData)
+        {
+            var eventArgs = new CameraProcessEventArgsResultModel
+            {
+                CameraId = this.CameraId,
+                ResultData = resultData,
+                Timestamp = DateTime.Now
+            };
+
+            // 触发事件,通知订阅者有新的处理结果
+            ProcessResultAvailable?.Invoke(this, eventArgs);
+        }
+
+        /// <summary>
+        /// 启动相机组(包括采集和处理线程)
+        /// </summary>
+        public void Start()
+        {
+            if (Camera == null)
+            {
+                Console.WriteLine($"相机 {CameraId} 未初始化");
+                return;
+            }
+            if(Camera.Device == null)
+            {
+                Console.WriteLine($"相机 {CameraId} 未初始化");
+            }
+            if (Camera.Device.IsConnected == false)
+            {
+                Console.WriteLine($"相机 {CameraId} 未打开");
+                return;
+            }
+            if (IsRunning)
+                return;
+
+            Camera.StartReceiveFuntion();
+
+            // 重置取消令牌
+            CancellationTokenSource = new CancellationTokenSource();
+            var token = CancellationTokenSource.Token;
+
+            // 启动相机采集线程
+            CameraTask = Task.Factory.StartNew(() => CameraCaptureLoop(token),
+                token, TaskCreationOptions.LongRunning, TaskScheduler.Default);
+
+            // 启动图像处理线程
+            ProcessingTask = Task.Factory.StartNew(() => ImageProcessingLoop(token),
+                token, TaskCreationOptions.LongRunning, TaskScheduler.Default);
+
+            IsRunning = true;
+            Console.WriteLine($"相机组 {CameraId} 已启动");
+        }
+
+        /// <summary>
+        /// 停止相机组
+        /// </summary>
+        public async void Stop()
+        {
+            if (!IsRunning)
+                return;
+
+            // 发送取消信号
+            CancellationTokenSource.Cancel();
+
+            // 等待线程完成
+            try
+            {
+                if (CameraTask != null)
+                    await CameraTask;
+
+                if (ProcessingTask != null)
+                    await ProcessingTask;
+            }
+            catch (OperationCanceledException)
+            {
+                // 正常取消,忽略异常
+            }
+
+            IsRunning = false;
+            Camera.StopReceiveFuntion();
+            Console.WriteLine($"相机组 {CameraId} 已停止");
+        }
+
+        /// <summary>
+        /// 相机采集循环
+        /// </summary>
+        private void CameraCaptureLoop(CancellationToken token)
+        {
+            //int frameCount = 0;
+            try
+            {
+                while (!token.IsCancellationRequested)
+                {
+                    // 模拟相机图像采集(无休眠,持续采集)
+                    if(Camera.GetOnceImage(out IFrameOut imageData))
+                    {
+                        // 将图像放入队列
+                        ImageQueue.Enqueue(imageData.Image.Clone() as IImage);
+                        Console.WriteLine($"相机 {CameraId} 采集到图像,帧号{imageData.FrameNum}");
+                        QueueSemaphore.Release(); // 通知处理线程有新数据
+                        imageData.Dispose();
+                    }
+                    // 这里不添加休眠,保持最大帧率采集
+                }
+            }
+            catch (OperationCanceledException)
+            {
+                // 线程被取消,正常退出
+            }
+            catch (Exception ex)
+            {
+                Console.WriteLine($"相机 {CameraId} 采集异常: {ex.Message}");
+            }
+        }
+
+        /// <summary>
+        /// 图像处理循环
+        /// </summary>
+        private async void ImageProcessingLoop(CancellationToken token)
+        {
+            try
+            {
+                while (!token.IsCancellationRequested)
+                {
+                    // 等待图像数据
+                    await QueueSemaphore.WaitAsync(token);
+
+                    // 从队列获取图像
+                    if (ImageQueue.TryDequeue(out IImage imageData))
+                    {
+                        // 执行图像处理逻辑
+                        ProcessImage(imageData, CameraId);
+                        imageData.Dispose();
+
+                        // 可以根据队列长度决定是否短暂休眠以避免过度占用CPU
+                        if (ImageQueue.Count == 0)
+                        {
+                            await Task.Delay(1, token); // 短暂让出CPU
+                        }
+                    }
+                }
+            }
+            catch (OperationCanceledException)
+            {
+                // 线程被取消,正常退出
+            }
+            catch (Exception ex)
+            {
+                Console.WriteLine($"相机 {CameraId} 处理异常: {ex.Message}");
+            }
+        }
+
+        /// <summary>
+        /// 图像处理实现
+        /// </summary>
+        private void ProcessImage(IImage imageData,int cameraId)
+        {
+            object resultData = null;
+
+            try
+            {
+                // 优先使用接口方式的算法
+                if (ImageProcessor != null)
+                {
+                    resultData = ImageProcessor.ProcessImage(imageData,cameraId);
+                }
+                // 如果都没有设置,则使用默认处理
+                else
+                {
+                    // 默认处理逻辑
+                }
+
+                // 发送处理结果
+                SendProcessResult(resultData);
+
+                // 输出处理结果
+                //Console.WriteLine($"相机 {CameraId} 处理时间 {DateTime.Now.ToString("g")}");
+            }
+            catch (Exception ex)
+            {
+                Console.WriteLine($"相机 {CameraId} 图像处理错误: {ex.Message}");
+
+                // 发送错误结果
+                //var errorResult = new ProcessResultData
+                //{
+                //    Result = $"Error_Camera{CameraId}_Frame{imageData.FrameNumber}_{ex.Message}",
+                //    ProcessingTime = DateTime.Now
+                //};
+
+                //SendProcessResult(errorResult);
+            }
+        }
+    }
+}

+ 113 - 0
MvvmScaffoldFrame48.DLL/ThreadManager/CommunicationThread.cs

@@ -0,0 +1,113 @@
+using MvvmScaffoldFrame48.Model.ResultModel;
+using System;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace MvvmScaffoldFrame48.DLL.ThreadManager
+{
+    /// <summary>
+    /// 通信线程管理类
+    /// 管理通信线程的生命周期和数据传输
+    /// </summary>
+    public class CommunicationThread
+    {
+        public bool IsRunning { get; private set; }
+        public CancellationTokenSource CancellationTokenSource { get; private set; }
+        public Task CommunicationTask { get; private set; }
+
+        // 待发送数据队列
+        private readonly ConcurrentQueue<CameraProcessEventArgsResultModel> _dataQueue = new ConcurrentQueue<CameraProcessEventArgsResultModel>();
+        private readonly SemaphoreSlim _queueSemaphore = new SemaphoreSlim(0);
+
+        /// <summary>
+        /// 发送数据到通信设备
+        /// </summary>
+        public void SendData(CameraProcessEventArgsResultModel data)
+        {
+            _dataQueue.Enqueue(data);
+            _queueSemaphore.Release();
+        }
+
+        /// <summary>
+        /// 启动通信线程
+        /// </summary>
+        public void Start()
+        {
+            if (IsRunning)
+                return;
+
+            CancellationTokenSource = new CancellationTokenSource();
+            var token = CancellationTokenSource.Token;
+
+            CommunicationTask = Task.Factory.StartNew(() => CommunicationLoop(token),
+                token, TaskCreationOptions.LongRunning, TaskScheduler.Default);
+
+            IsRunning = true;
+            Console.WriteLine("通信线程已启动");
+        }
+
+        /// <summary>
+        /// 停止通信线程
+        /// </summary>
+        public async void Stop()
+        {
+            if (!IsRunning)
+                return;
+
+            CancellationTokenSource.Cancel();
+
+            try
+            {
+                if (CommunicationTask != null)
+                    await CommunicationTask;
+            }
+            catch (OperationCanceledException)
+            {
+                // 正常取消
+            }
+
+            IsRunning = false;
+            Console.WriteLine("通信线程已停止");
+        }
+
+        private async void CommunicationLoop(CancellationToken token)
+        {
+            try
+            {
+                while (!token.IsCancellationRequested)
+                {
+                    // 等待数据
+                    await _queueSemaphore.WaitAsync(token);
+
+                    // 从队列获取数据
+                    if (_dataQueue.TryDequeue(out CameraProcessEventArgsResultModel data))
+                    {
+                        // 执行通信逻辑
+                        PerformCommunication(data);
+                    }
+
+                    // 1ms休眠
+                    await Task.Delay(1, token);
+                }
+            }
+            catch (OperationCanceledException)
+            {
+                // 线程被取消,正常退出
+            }
+            catch (Exception ex)
+            {
+                Console.WriteLine($"通信线程异常: {ex.Message}");
+            }
+        }
+
+        private void PerformCommunication(CameraProcessEventArgsResultModel data)
+        {
+            // 实现具体通信逻辑
+            Console.WriteLine($"通信线程发送数据: 相机{data.CameraId}, 时间{data.Timestamp}");
+        }
+    }
+}

+ 24 - 0
MvvmScaffoldFrame48.DLL/ThreadManager/IImageProcessingAlgorithmHikVision.cs

@@ -0,0 +1,24 @@
+using MvCameraControl;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace MvvmScaffoldFrame48.DLL.ThreadManager
+{
+    public interface IImageProcessingAlgorithmHikVision
+    {
+        /// <summary>
+        /// 处理图像数据
+        /// </summary>
+        /// <param name="imageData">输入的图像数据</param>
+        /// <returns>处理结果</returns>
+        object ProcessImage(IImage imageData,int cameraId);
+
+        /// <summary>
+        /// 获取算法名称
+        /// </summary>
+        string AlgorithmName { get; }
+    }
+}

+ 30 - 0
MvvmScaffoldFrame48.DLL/ThreadManager/ProcessingAlgorithm.cs

@@ -0,0 +1,30 @@
+using MvCameraControl;
+using MvvmScaffoldFrame48.Model.ResultModel;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace MvvmScaffoldFrame48.DLL.ThreadManager
+{
+    public class ProcessingAlgorithm : IImageProcessingAlgorithmHikVision
+    {
+        public string AlgorithmName => "ProcessingAlgorithm";
+
+        public object ProcessImage(IImage imageData,int cameraId)
+        {
+            // 模拟算法A的处理逻辑
+            Thread.Sleep(1); // 模拟处理时间
+            Console.WriteLine("相机执行了一次识别");
+
+            return new CameraProcessEventArgsResultModel
+            {
+                CameraId = cameraId,
+                ResultData = $"ProcessingAlgorithm_Processed_Camera{cameraId}",
+                Timestamp = DateTime.Now
+            };
+        }
+    }
+}

+ 128 - 0
MvvmScaffoldFrame48.DLL/ThreadManager/ThreadManager.cs

@@ -0,0 +1,128 @@
+using MvCameraControl;
+using MvvmScaffoldFrame48.DLL.CameraTools;
+using MvvmScaffoldFrame48.Model.ResultModel;
+using System;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace MvvmScaffoldFrame48.DLL.ThreadManager
+{
+    public class ThreadManager
+    {
+        private readonly CameraGroup[] _cameraGroups = new CameraGroup[1];
+        private readonly CommunicationThread _communicationThread;
+
+        public ThreadManager()
+        {
+            HikVision.GetCameraList(out List<IDeviceInfo> cameraInfoList);
+            // 初始化四个相机组
+            for (int i = 0; i < _cameraGroups.Count(); i++)
+            {
+                _cameraGroups[i] = new CameraGroup
+                {
+                    CameraId = i,
+                    ImageQueue = new ConcurrentQueue<IImage>(),
+                    QueueSemaphore = new SemaphoreSlim(0),
+                    Camera = new HikCamera(cameraInfoList[i])
+                };
+
+                _cameraGroups[i].ImageProcessor = new ProcessingAlgorithm();
+                // 订阅处理结果事件
+                _cameraGroups[i].ProcessResultAvailable += OnProcessResultAvailable;
+            }
+
+            // 初始化通信和显示线程
+            _communicationThread = new CommunicationThread();
+        }
+
+        /// <summary>
+        /// 处理相机处理结果
+        /// </summary>
+        private void OnProcessResultAvailable(object sender, CameraProcessEventArgsResultModel e)
+        {
+            // 将处理结果发送到通信线程
+            _communicationThread.SendData(e);
+
+            // 可以在这里添加其他处理逻辑,如更新显示等
+            Console.WriteLine($"收到相机{e.CameraId}的处理结果");
+        }
+
+        /// <summary>
+        /// 启动指定相机组
+        /// </summary>
+        public void StartCameraGroup(int cameraId)
+        {
+            if (cameraId >= 0 && cameraId < _cameraGroups.Count())
+            {
+                _cameraGroups[cameraId].Start();
+            }
+        }
+
+        /// <summary>
+        /// 停止指定相机组
+        /// </summary>
+        public void StopCameraGroup(int cameraId)
+        {
+            if (cameraId >= 0 && cameraId < 4)
+            {
+                _cameraGroups[cameraId].Stop();
+            }
+        }
+
+        /// <summary>
+        /// 启动通信线程
+        /// </summary>
+        public void StartCommunication()
+        {
+            _communicationThread.Start();
+        }
+
+        /// <summary>
+        /// 停止通信线程
+        /// </summary>
+        public void StopCommunication()
+        {
+            _communicationThread.Stop();
+        }
+
+        /// <summary>
+        /// 启动所有线程
+        /// </summary>
+        public void StartAll()
+        {
+            for (int i = 0; i < 4; i++)
+            {
+                StartCameraGroup(i);
+            }
+            StartCommunication();
+        }
+
+        /// <summary>
+        /// 停止所有线程
+        /// </summary>
+        public void StopAll()
+        {
+            for (int i = 0; i < 4; i++)
+            {
+                StopCameraGroup(i);
+            }
+            StopCommunication();
+        }
+
+        /// <summary>
+        /// 获取相机组运行状态
+        /// </summary>
+        public bool IsCameraGroupRunning(int cameraId)
+        {
+            return cameraId >= 0 && cameraId < 4 && _cameraGroups[cameraId].IsRunning;
+        }
+
+        /// <summary>
+        /// 获取通信线程运行状态
+        /// </summary>
+        public bool IsCommunicationRunning => _communicationThread.IsRunning;
+    }
+}

+ 1 - 1
MvvmScaffoldFrame48.MODEL/MvvmScaffoldFrame48.Model.csproj

@@ -61,6 +61,7 @@
     <Reference Include="System.Xml" />
   </ItemGroup>
   <ItemGroup>
+    <Compile Include="ResultModel\CameraProcessEventArgsResultModel.cs" />
     <Compile Include="StorageModel\AuditTrail\ErrorMessageRecordModel.cs" />
     <Compile Include="StorageModel\AuditTrail\OperationRecordModel.cs" />
     <Compile Include="StorageModel\HikVisionCamera\CameraImageSizeCModel.cs" />
@@ -75,7 +76,6 @@
   </ItemGroup>
   <ItemGroup>
     <Folder Include="RequestModel\" />
-    <Folder Include="ResultModel\" />
   </ItemGroup>
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
 </Project>

+ 30 - 0
MvvmScaffoldFrame48.MODEL/ResultModel/CameraProcessEventArgsResultModel.cs

@@ -0,0 +1,30 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace MvvmScaffoldFrame48.Model.ResultModel
+{
+    /// <summary>
+    /// 处理结果事件参数类
+    /// 包含相机ID和处理结果数据
+    /// </summary>
+    public class CameraProcessEventArgsResultModel : EventArgs
+    {
+        /// <summary>
+        /// 相机ID
+        /// </summary>
+        public int CameraId { get; set; }
+
+        /// <summary>
+        /// 处理结果数据
+        /// </summary>
+        public object ResultData { get; set; }
+
+        /// <summary>
+        /// 结果生成时间戳
+        /// </summary>
+        public DateTime Timestamp { get; set; }
+    }
+}

+ 15 - 0
MvvmScaffoldFrame48.VIEWMODEL/ViewModel/CustomControlViewModel.cs

@@ -29,6 +29,20 @@ namespace MvvmScaffoldFrame48.ViewModel.ViewModel
                 }
             }
         }
+
+        private ObservableCollection<string> _formulationItems = new ObservableCollection<string>();
+        public ObservableCollection<string> FormulationItems 
+        {
+            get { return _formulationItems;}
+            set
+            {
+                if (_formulationItems != value)
+                {
+                    _formulationItems = value;
+                    OnPropertyChanged(nameof(FormulationItems));
+                }
+            }
+        }
         #endregion
 
         #region 界面绑定事件
@@ -57,6 +71,7 @@ namespace MvvmScaffoldFrame48.ViewModel.ViewModel
         public CustomControlViewModel()
         {
             TestCommand = new RelayCommand(Test, CanTest);
+            FormulationItems.Add("1");
         }
         #endregion
 

+ 15 - 0
MvvmScaffoldFrame48.VIEWMODEL/ViewModel/MainViewModel.cs

@@ -1,4 +1,13 @@
 // 演示类
+using MvvmScaffoldFrame48.DLL;
+using MvvmScaffoldFrame48.DLL.AuditTrail;
+using MvvmScaffoldFrame48.DLL.ThreadManager;
+using MvvmScaffoldFrame48.DLL.WindowsTools;
+using MvvmScaffoldFrame48.Model;
+using MvvmScaffoldFrame48.Model.StorageModel.AuditTrail;
+using System;
+using System.Collections.ObjectModel;
+using System.Windows.Input;
 
 namespace MvvmScaffoldFrame48.ViewModel.ViewModel
 {
@@ -28,6 +37,12 @@ namespace MvvmScaffoldFrame48.ViewModel.ViewModel
         #endregion
 
         #region 其他方法
+        public MainViewModel()
+        {
+            ThreadManager MainThreadManager = new ThreadManager();
+            MainThreadManager.StartCameraGroup(0);
+            MainThreadManager.StartCommunication();
+        }
         #endregion
     }
 }

+ 2 - 0
MvvmScaffoldFrame48/WPFFroms/MainWindow.xaml.cs

@@ -13,6 +13,8 @@ namespace MvvmScaffoldFrame48
         public MainWindow()
         {
             InitializeComponent();
+            MainViewModel mainViewModel = new MainViewModel();
+            this.DataContext = mainViewModel;
         }
 
         private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)