using AnQing.Commons; using AnQing.Models; using Modbus.Device; using MvCamCtrl.NET; using RGD.DBUtility; using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Data.SqlClient; using System.Drawing; using System.Drawing.Imaging; using System.IO; using System.IO.Ports; using System.Linq; using System.Runtime.InteropServices; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Controls.Primitives; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Threading; using ZXing; using ZXing.Common; using static System.Net.Mime.MediaTypeNames; using Application = System.Windows.Application; using Color = System.Drawing.Color; using PixelFormat = System.Drawing.Imaging.PixelFormat; namespace AnQing.ViewModel { public class MianWindowViewModel : INotifyPropertyChanged { #region 属性 /// /// 图片识别区域 /// public List possibleRegions = new List(); /// /// 摄像头1连接状态 /// private bool video1State; public bool Video1State { get { return video1State; } set { video1State = value; OnPropertyChanged("Video1State"); } } /// /// 摄像头2连接状态 /// private bool video2State; public bool Video2State { get { return video2State; } set { video2State = value; OnPropertyChanged("Video2State"); } } /// /// 识别状态 /// private bool readerState; public bool ReaderState { get { return readerState; } set { readerState = value; OnPropertyChanged("ReaderState"); } } /// /// 识别到的数据信息 /// private string readerText; public string ReaderText { get { return readerText; } set { readerText = value; OnPropertyChanged("ReaderText"); } } private string readerText_temp; /// /// 识别时间 /// private string readerTextTime; public string ReaderTextTime { get { return readerTextTime; } set { readerTextTime = value; OnPropertyChanged("ReaderTextTime"); } } /// /// 图像一 /// private ImageSource _imageSource; public ImageSource ImageSource { get { return _imageSource; } set { if (_imageSource != value) { if (_imageSource is BitmapSource oldBitmapSource) { DisposeBitmapSource(oldBitmapSource); } _imageSource = value; OnPropertyChanged(nameof(ImageSource)); } } } /// /// 释放 BitmapSource 资源,避免 GDI 资源泄漏 /// private void DisposeBitmapSource(BitmapSource bitmapSource) { if (bitmapSource == null) return; if (bitmapSource is IDisposable disposable) { disposable.Dispose(); } } /// /// 图像二 /// private ImageSource _imageSource2; public ImageSource ImageSource2 { get { return _imageSource2; } set { if (_imageSource2 != value) { _imageSource2 = value; OnPropertyChanged(nameof(ImageSource2)); } } } #endregion #region 事件 /// /// 摄像触发采集 /// private ICommand buttonGatherCommand; public ICommand ButtonGatherCommand => buttonGatherCommand ??= new RelayCommand(TriggerExec); /// /// 释放 /// private ICommand buttonCloseCommand; public ICommand ButtonCloseCommand => buttonCloseCommand ??= new RelayCommand(CloseCamera); #endregion #region 相机初始化 //图像一 MyCamera.MV_CC_DEVICE_INFO_LIST m_stDeviceList = new MyCamera.MV_CC_DEVICE_INFO_LIST(); public MyCamera m_MyCamera = new MyCamera(); bool m_bGrabbing = false; //图像二 public MyCamera m_MyCamera2 = new MyCamera(); bool m_bGrabbing2 = false; /// /// 关闭程序需要关闭摄像头 /// private void CloseCamera() { // ch:关闭设备 | en:Close Device m_MyCamera.MV_CC_CloseDevice_NET(); m_MyCamera.MV_CC_DestroyDevice_NET(); } /// /// 初始化打开摄像头 /// private void OpenCamera() { string targetIp = "192.168.2.11"; // 摄像头IP string targetIp2 = "192.168.3.13"; // 摄像头2 IP bool ip1 = false, ip2 = false; System.GC.Collect(); m_stDeviceList.nDeviceNum = 0; int nRet1 = MyCamera.MV_CC_EnumDevices_NET(MyCamera.MV_GIGE_DEVICE | MyCamera.MV_USB_DEVICE, ref m_stDeviceList); if (nRet1 != 0) { MessageBox.Show("MV_CC_EnumDevices_NET 初始化失败: " + nRet1); return; } // ch:获取选择的设备信息 | en:Get selected device information MyCamera.MV_CC_DEVICE_INFO device = new MyCamera.MV_CC_DEVICE_INFO();//相机一 MyCamera.MV_CC_DEVICE_INFO device2 = new MyCamera.MV_CC_DEVICE_INFO();//相机二 for (int i = 0; i < m_stDeviceList.nDeviceNum; i++) { MyCamera.MV_CC_DEVICE_INFO device_temp = (MyCamera.MV_CC_DEVICE_INFO)Marshal.PtrToStructure(m_stDeviceList.pDeviceInfo[i], typeof(MyCamera.MV_CC_DEVICE_INFO)); if (device_temp.nTLayerType == MyCamera.MV_GIGE_DEVICE) { MyCamera.MV_GIGE_DEVICE_INFO_EX gigeInfo = (MyCamera.MV_GIGE_DEVICE_INFO_EX)MyCamera.ByteToStruct(device_temp.SpecialInfo.stGigEInfo, typeof(MyCamera.MV_GIGE_DEVICE_INFO_EX)); string deviceIp = $"{(gigeInfo.nCurrentIp >> 24) & 0xFF}.{(gigeInfo.nCurrentIp >> 16) & 0xFF}.{(gigeInfo.nCurrentIp >> 8) & 0xFF}.{gigeInfo.nCurrentIp & 0xFF}"; if (deviceIp == targetIp) // 相机一 { device = (MyCamera.MV_CC_DEVICE_INFO)Marshal.PtrToStructure(m_stDeviceList.pDeviceInfo[i], typeof(MyCamera.MV_CC_DEVICE_INFO)); ip1 = true; } if (deviceIp == targetIp2) // 相机二 { device2 = (MyCamera.MV_CC_DEVICE_INFO)Marshal.PtrToStructure(m_stDeviceList.pDeviceInfo[i], typeof(MyCamera.MV_CC_DEVICE_INFO)); ip2 = true; } } } // ch:打开设备 | en:Open device if (null == m_MyCamera) { m_MyCamera = new MyCamera(); if (null == m_MyCamera) { return; } } if (null == m_MyCamera2) { m_MyCamera2 = new MyCamera(); if (null == m_MyCamera2) { return; } } int nRet = m_MyCamera.MV_CC_CreateDevice_NET(ref device); if (MyCamera.MV_OK != nRet) { return; } nRet = m_MyCamera.MV_CC_OpenDevice_NET(); if (MyCamera.MV_OK != nRet) { m_MyCamera.MV_CC_CloseDevice_NET(); m_MyCamera.MV_CC_DestroyDevice_NET(); //// ch:关闭设备 | en:Close Device m_MyCamera2.MV_CC_CloseDevice_NET(); m_MyCamera2.MV_CC_DestroyDevice_NET(); return; } int nRet_2 = m_MyCamera2.MV_CC_CreateDevice_NET(ref device2); if (MyCamera.MV_OK != nRet_2) { return; } nRet_2 = m_MyCamera2.MV_CC_OpenDevice_NET(); if (MyCamera.MV_OK != nRet_2) { m_MyCamera.MV_CC_CloseDevice_NET(); m_MyCamera.MV_CC_DestroyDevice_NET(); //// ch:关闭设备 | en:Close Device m_MyCamera2.MV_CC_CloseDevice_NET(); m_MyCamera2.MV_CC_DestroyDevice_NET(); return; } // ch:探测网络最佳包大小(只对GigE相机有效) | en:Detection network optimal package size(It only works for the GigE camera) if (device.nTLayerType == MyCamera.MV_GIGE_DEVICE) { int nPacketSize = m_MyCamera.MV_CC_GetOptimalPacketSize_NET(); if (nPacketSize > 0) { nRet = m_MyCamera.MV_CC_SetIntValueEx_NET("GevSCPSPacketSize", nPacketSize); if (nRet != MyCamera.MV_OK) { MessageBox.Show("MV_CC_SetIntValueEx_NET 初始化失败: " + nRet); } } else { MessageBox.Show("MV_CC_SetIntValueEx_NET 初始化失败: " + nPacketSize); } } if (device2.nTLayerType == MyCamera.MV_GIGE_DEVICE) { int nPacketSize = m_MyCamera2.MV_CC_GetOptimalPacketSize_NET(); if (nPacketSize > 0) { nRet_2 = m_MyCamera2.MV_CC_SetIntValueEx_NET("GevSCPSPacketSize", nPacketSize); if (nRet_2 != MyCamera.MV_OK) { MessageBox.Show("MV_CC_SetIntValueEx_NET 初始化失败: " + nRet_2); } } else { MessageBox.Show("MV_CC_SetIntValueEx_NET 初始化失败: " + nPacketSize); } } // ch:设置采集连续模式 | en:Set Continues Aquisition Mode m_MyCamera.MV_CC_SetEnumValue_NET("AcquisitionMode", (uint)MyCamera.MV_CAM_ACQUISITION_MODE.MV_ACQ_MODE_CONTINUOUS); m_MyCamera.MV_CC_SetEnumValue_NET("TriggerMode", (uint)MyCamera.MV_CAM_TRIGGER_MODE.MV_TRIGGER_MODE_ON); m_MyCamera.MV_CC_SetEnumValue_NET("TriggerSource", (uint)MyCamera.MV_CAM_TRIGGER_SOURCE.MV_TRIGGER_SOURCE_SOFTWARE); m_MyCamera2.MV_CC_SetEnumValue_NET("AcquisitionMode", (uint)MyCamera.MV_CAM_ACQUISITION_MODE.MV_ACQ_MODE_CONTINUOUS); m_MyCamera2.MV_CC_SetEnumValue_NET("TriggerMode", (uint)MyCamera.MV_CAM_TRIGGER_MODE.MV_TRIGGER_MODE_ON); m_MyCamera2.MV_CC_SetEnumValue_NET("TriggerSource", (uint)MyCamera.MV_CAM_TRIGGER_SOURCE.MV_TRIGGER_SOURCE_SOFTWARE); //bnGetParam_Click(null, null);//获取相机焦距等参数 // ch:标志位置位true | en:Set position bit true m_bGrabbing = true; m_bGrabbing2 = true; // ch:开始采集 | en:Start Grabbing int nRet2 = m_MyCamera.MV_CC_StartGrabbing_NET(); if (MyCamera.MV_OK != nRet2) { m_bGrabbing = false; MessageBox.Show("MV_CC_StartGrabbing_NET 初始化失败: " + nRet2); return; } int nRet2_2 = m_MyCamera2.MV_CC_StartGrabbing_NET(); if (MyCamera.MV_OK != nRet2_2) { m_bGrabbing2 = false; MessageBox.Show("MV_CC_StartGrabbing_NET 初始化失败: " + nRet2_2); return; } if (ip1) Video1State = true; if (ip2) Video2State = true; } private List ReadImageGuid_Temp = new List (); public string ReaderImagePath_Temp; /// /// 抓拍图片 /// public void ReceiveThreadProcess() { MyCamera.MV_FRAME_OUT stFrameInfo = new MyCamera.MV_FRAME_OUT(); int nRet = m_MyCamera.MV_CC_GetImageBuffer_NET(ref stFrameInfo, 1000); if (nRet == MyCamera.MV_OK) { try { int width = stFrameInfo.stFrameInfo.nWidth; int height = stFrameInfo.stFrameInfo.nHeight; int stride = width; // Mono8: 每个像素1字节,stride = width // 直接利用内存地址创建 Bitmap 对象 Bitmap bitmap = new Bitmap(width, height, stride, PixelFormat.Format8bppIndexed, stFrameInfo.pBufAddr); // 设置灰度调色板 ColorPalette palette = bitmap.Palette; for (int i = 0; i < 256; i++) { palette.Entries[i] = Color.FromArgb(i, i, i); } bitmap.Palette = palette; DateTime start = DateTime.Now; var reader = new BarcodeReader { AutoRotate = true, Options = new DecodingOptions { TryHarder = true, // 深度解析模式 PureBarcode = false, // 是否纯条码(无文字干扰) AssumeCode39CheckDigit = false, // 是否验证Code39校验位 PossibleFormats = new List { BarcodeFormat.CODE_128 //BarcodeFormat.EAN_13, //BarcodeFormat.EAN_8, //BarcodeFormat.UPC_A, //BarcodeFormat.UPC_E, //BarcodeFormat.CODE_39, //BarcodeFormat.ITF, //BarcodeFormat.CODABAR }, CharacterSet = "UTF-8" } }; foreach (var region in possibleRegions) { Bitmap cropped = CropBarcodeRegion(bitmap, region); var result = reader.Decode(cropped); cropped.Dispose(); cropped = null; if (result != null) { readerText_temp = result.Text; ReaderText = result.Text; ReaderState = false; break; } else { readerText_temp = ""; } } if (string.IsNullOrEmpty(readerText_temp)) { ReaderText = "未检测到条码!"; ReaderState = true; } DateTime end = DateTime.Now; TimeSpan duration = end - start; ReaderTextTime = duration.TotalSeconds.ToString() + " 秒"; Application.Current.Dispatcher.Invoke(() => { // 转换为 WPF BitmapImage 用于 Image 控件显示 ImageSource = Common.BitmapToBitmapSource2(bitmap); }); string guid = Guid.NewGuid().ToString(); ReaderImagePath_Temp = AppDomain.CurrentDomain.BaseDirectory + "ImageList\\" + DateTime.Now.ToString("yyyy-MM-dd") + "\\" + guid + ".jpeg"; string imgpath_after = ""; string sql = @" IF NOT EXISTS (SELECT 1 FROM SCAN_MIAN WHERE goodcode = @goodcode) BEGIN INSERT INTO SCAN_MIAN (time, goodcode, img, img_after, ex) VALUES (@time, @goodcode, @img, @img_after, @ex) END"; SqlParameter[] parameters = { new SqlParameter("@time", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")), new SqlParameter("@goodcode", readerText_temp), new SqlParameter("@img", ReaderImagePath_Temp), new SqlParameter("@img_after", imgpath_after), new SqlParameter("@ex", guid) }; DbHelperSQL.ExecuteSql(sql, parameters); DbHelperSQL.ExecuteSql($"INSERT INTO SCAN_MIAN (time, goodcode, img, img_after,ex) VALUES ('{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}', '{readerText_temp}', '{ReaderImagePath_Temp}', '{imgpath_after}','{guid}');"); ReadImageGuid_Temp.Add(guid); // 直接将图像数据保存到本地(例如保存为 JPEG 格式) SaveBitmapToFile(bitmap, ReaderImagePath_Temp); bitmap.Dispose(); bitmap = null; } catch (Exception ex) { MessageBox.Show("图像处理失败: " + ex.Message); } finally { m_MyCamera.MV_CC_FreeImageBuffer_NET(ref stFrameInfo); } } else { MessageBox.Show("获取图像失败,错误码:" + nRet); } } public string ReaderImagePath_Temp2; /// /// 抓拍图片 左相机 /// public void ReceiveThreadProcess2() { MyCamera.MV_FRAME_OUT stFrameInfo = new MyCamera.MV_FRAME_OUT(); int nRet = m_MyCamera2.MV_CC_GetImageBuffer_NET(ref stFrameInfo, 1000); if (nRet == MyCamera.MV_OK) { try { int width = stFrameInfo.stFrameInfo.nWidth; int height = stFrameInfo.stFrameInfo.nHeight; int stride = width; // Mono8: 每个像素1字节,stride = width // 直接利用内存地址创建 Bitmap 对象 Bitmap bitmap = new Bitmap(width, height, stride, PixelFormat.Format8bppIndexed, stFrameInfo.pBufAddr); // 设置灰度调色板 ColorPalette palette = bitmap.Palette; for (int i = 0; i < 256; i++) { palette.Entries[i] = Color.FromArgb(i, i, i); } bitmap.Palette = palette; Application.Current.Dispatcher.Invoke(() => { // 转换为 WPF BitmapImage 用于 Image 控件显示 ImageSource2 = Common.BitmapToBitmapSource2(bitmap); }); ReaderImagePath_Temp2 = AppDomain.CurrentDomain.BaseDirectory + "ImageList\\" + DateTime.Now.ToString("yyyy-MM-dd") + "\\" + Guid.NewGuid() + ".jpeg"; //DbHelperSQL.ExecuteSql($"update SCAN_MIAN set img_after='{ReaderImagePath_Temp2}' WHERE id = (SELECT id FROM ( SELECT id FROM SCAN_MIAN ORDER BY id DESC OFFSET 2 ROWS FETCH NEXT 1 ROWS ONLY ) AS subquery)"); DbHelperSQL.ExecuteSql($"update SCAN_MIAN set img_after='{ReaderImagePath_Temp2}' WHERE ex = '{ReadImageGuid_Temp[0]}'"); ReadImageGuid_Temp.Remove(ReadImageGuid_Temp[0]); // 直接将图像数据保存到本地(例如保存为 JPEG 格式) SaveBitmapToFile(bitmap, ReaderImagePath_Temp2); bitmap.Dispose(); bitmap = null; } catch (Exception ex) { MessageBox.Show("图像处理失败: " + ex.Message); } finally { m_MyCamera.MV_CC_FreeImageBuffer_NET(ref stFrameInfo); } } else { MessageBox.Show("获取图像失败,错误码:" + nRet); } } /// /// 直接将图像保存为文件 /// /// /// private void SaveBitmapToFile(Bitmap bitmap, string filePath) { // 使用 MemoryStream 保存图像,减少内存占用 using (MemoryStream ms = new MemoryStream()) { bitmap.Save(ms, ImageFormat.Jpeg); // 保存为 JPEG 格式 File.WriteAllBytes(filePath, ms.ToArray()); } } /// /// 触发拍照指令 右相机 /// public void TriggerExec() { string sql = @" IF NOT EXISTS (SELECT 1 FROM SCAN_MIAN WHERE goodcode = @goodcode) BEGIN INSERT INTO SCAN_MIAN (time, goodcode, img, img_after, ex) VALUES (@time, @goodcode, @img, @img_after, @ex) END"; SqlParameter[] parameters = { new SqlParameter("@time", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")), new SqlParameter("@goodcode", "123"), new SqlParameter("@img", "321"), new SqlParameter("@img_after", "imgpath_after"), new SqlParameter("@ex", "guid") }; DbHelperSQL.ExecuteSql(sql, parameters); //// ch:触发命令 | en:Trigger command //int nRet = m_MyCamera.MV_CC_SetCommandValue_NET("TriggerSoftware"); //if (MyCamera.MV_OK != nRet) //{ // //ShowErrorMsg("Trigger Software Fail!", nRet); //} //if (m_bGrabbing) //{ // Task.Run(() => { // ReceiveThreadProcess(); // }); //} //TriggerExec_Left(); } /// /// 触发拍照指令 左相机 /// public void TriggerExec_Left() { // ch:触发命令 | en:Trigger command int nRet = m_MyCamera2.MV_CC_SetCommandValue_NET("TriggerSoftware"); if (MyCamera.MV_OK != nRet) { //ShowErrorMsg("Trigger Software Fail!", nRet); } if (m_bGrabbing2) { Task.Run(() => { ReceiveThreadProcess2(); }); } } public static Bitmap CropBarcodeRegion(Bitmap original, Rectangle roi) { // 确保裁剪区域在图片范围内 roi.Intersect(new Rectangle(0, 0, original.Width, original.Height)); // 进行裁剪 return original.Clone(roi, original.PixelFormat); } #endregion #region 通讯数据 private SerialPort _serialPort; private IModbusSerialMaster _modbusMaster; private DispatcherTimer _timer; private bool _leftCameraTriggered; public bool LeftCameraTriggered { get => _leftCameraTriggered; set { _leftCameraTriggered = value; OnPropertyChanged("LeftCameraTriggered"); } } private bool _rightCameraTriggered; public bool RightCameraTriggered { get => _rightCameraTriggered; set { _rightCameraTriggered = value; OnPropertyChanged("RightCameraTriggered"); } } /// /// 初始化连接PLC /// private void InitializeModbus() { try { // 创建并打开串口 _serialPort = new SerialPort("COM10", 115200, Parity.None, 8, StopBits.One); _serialPort.ReadTimeout = 1000; // 设置串口读取超时为1秒 _serialPort.WriteTimeout = 1000; // 设置串口写入超时为1秒 _serialPort.Open(); // 创建 Modbus 主站 _modbusMaster = ModbusSerialMaster.CreateRtu(_serialPort); _modbusMaster.Transport.Retries = 3; _modbusMaster.Transport.WaitToRetryMilliseconds = 100; _modbusMaster.Transport.SlaveBusyUsesRetryCount = true; Console.WriteLine("MODBUS 连接成功!"); } catch (Exception ex) { Console.WriteLine("MODBUS 连接失败: " + ex.Message); } } /// /// 线程 监听接收信息 /// private void StartPolling() { _timer = new DispatcherTimer { Interval = TimeSpan.FromMilliseconds(500) }; _timer.Tick += (s, e) => ReadPlcData(); _timer.Start(); } private async Task ReadHoldingRegistersWithRetry(byte slaveId, ushort startAddress, ushort numRegisters) { int retryCount = 3; int waitTimeMs = 100; ushort[] result = null; for (int i = 0; i < retryCount; i++) { try { result = _modbusMaster.ReadHoldingRegisters(slaveId, startAddress, numRegisters); return result; // 成功读取则返回结果 } catch (Exception ex) { Console.WriteLine($"Modbus 读取失败: {ex.Message}"); if (i < retryCount - 1) // 如果不是最后一次重试 { await Task.Delay(waitTimeMs); // 等待一段时间后重试 } } } return result; // 如果超过重试次数还没成功,可以返回 null 或处理失败逻辑 } /// /// 信息接收方法 /// private void ReadPlcData() { try { //return; byte slaveId = 3; // 站号3 //// 读取左相机寄存器VW2000(Modbus地址0) //ushort[] leftCameraRegisters = _modbusMaster.ReadHoldingRegisters(slaveId, 0, 1); //// 读取右相机寄存器VW2002(Modbus地址1) //ushort[] rightCameraRegisters = _modbusMaster.ReadHoldingRegisters(slaveId, 1, 1); // 一次性读取左相机和右相机的寄存器 ushort[] registers = _modbusMaster.ReadHoldingRegisters(slaveId, 0, 2); // 解析左相机信号(VW2000的第0位) LeftCameraTriggered = (registers[0] & 0x0001) != 0; // 解析右相机信号(VW2002的第1位) RightCameraTriggered = (registers[1] & 0x0002) != 0; // 触发拍照 if (RightCameraTriggered) TakePhoto("右相机"); if (LeftCameraTriggered) TakePhoto("左相机"); } catch (Exception ex) { Console.WriteLine("PLC 读取失败: " + ex.Message); } } /// /// 向上位机Y5/7发送右相机OK信号至PLC /// /// true=激活信号,false=关闭信号 public void SendRightCameraOkSignal() { try { byte slaveId = 3; // 站号3 ushort coilAddress = 7; // Y5/7的Modbus VW 2014 short value = 1; _modbusMaster.WriteSingleRegister(slaveId, coilAddress,(ushort)value); } catch (Exception ex) { Console.WriteLine("PLC信号发送失败: " + ex.Message); } } private DateTime lastLeftTriggerTime = DateTime.MinValue; // 左相机上次触发时间 private DateTime lastRightTriggerTime = DateTime.MinValue; // 右相机上次触发时间 /// /// 获取哪个相机要触发 /// /// private void TakePhoto(string camera) { DateTime currentTime = DateTime.Now; if (camera == "左相机") { // 判断左相机触发的间隔时间 if ((currentTime - lastLeftTriggerTime).TotalSeconds < 1) { Console.WriteLine("左相机触发太快,请稍等..."); return; } // 更新左相机的触发时间 lastLeftTriggerTime = currentTime; Console.WriteLine("左相机触发" + currentTime.ToString("yyyy-MM-dd HH:mm:ss")); TriggerExec_Left(); } else if (camera == "右相机") { // 判断右相机触发的间隔时间 if ((currentTime - lastRightTriggerTime).TotalSeconds < 1) { Console.WriteLine("右相机触发太快,请稍等..."); return; } // 更新右相机的触发时间 lastRightTriggerTime = currentTime; Console.WriteLine("右相机触发" + currentTime.ToString("yyyy-MM-dd HH:mm:ss")); TriggerExec(); } } public void Dispose() { // 停止定时器 _timer?.Stop(); // 释放 ModbusMaster 和串口资源 _modbusMaster?.Dispose(); if (_serialPort?.IsOpen == true) _serialPort.Close(); } #endregion public MianWindowViewModel() { GetPossibleRegions(); ////ch: 初始化SDK | en: Initialize SDK //MyCamera.MV_CC_Initialize_NET(); ////相机初始化 //OpenCamera(); //plc 通讯初始化 //InitializeModbus(); //StartPolling(); } /// /// 获取裁切范围 /// public void GetPossibleRegions() { possibleRegions.Clear(); DataView dv = DbHelperSQL.Query("select * from IMAGEINFO").Tables[0].DefaultView; foreach (DataRowView rowView in dv) { possibleRegions.Add(new Rectangle(int.Parse(rowView["x"].ToString()), int.Parse(rowView["y"].ToString()), int.Parse(rowView["width"].ToString()), int.Parse(rowView["height"].ToString()))); } } public event PropertyChangedEventHandler PropertyChanged; protected void OnPropertyChanged(string propertyName) { if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); } } } }