手把手一起使用WPF MVVM制作USB调试助手Demo

news2024/9/22 17:29:07

1、USB调试助手Demo

该Demo使用WPF框架,基于MVVM设计模式,实现USB调试助手,效果如图所示:

在这里插入图片描述
实现功能:上位机(USB调试助手)与下位机(ZYNQ)通过USB通信,实现收发数据
实验环境:Visual Studio 2022
控件库:HandyControl 手把手一起使用开源WPF控件HandyControl
USB库:LibUsbDotNet
完整工程:手把手一起使用WPF MVVM制作USB调试助手Demo完整工程文件

2、功能演示

该Demo代码结构如图所示,参照MVVM设计模式完成

在这里插入图片描述
项目运行后界面如图所示:

在这里插入图片描述

USB设备通过两个ID进行连接,默认ID为随机输入的,故直接点连接USB设备会弹出没有发现设备,如图所示:

在这里插入图片描述
下位机连接正常后,下拉框可以选择相应USB设备,如图所示:

在这里插入图片描述
发送和接收的字节数同样可以设置,如图所示:

在这里插入图片描述
设置完成后,点击连接USB设备即可,此时可以打开Bus Hound超级软件总线协议分析器,观察发送和接收数据,如图所示:

在这里插入图片描述
USB发送数据区输入数据,点击开始发送,可以看到Bus Hound显示已经发送,如图所示,发送数据格式之所以如此,是因为自定义了上位机与下位机的通信协议头帧、校验帧及尾帧:

在这里插入图片描述

点击开始接收,下位机将数据返回至上位机界面,同时Bus Hound显示已经接收的数据,两者一致,如图所示:

在这里插入图片描述

再次进行发送和接收数据:

在这里插入图片描述
最后,点击断开USB设备,如图所示:

在这里插入图片描述

3、UI界面XAML

UI界面代码MainWindow.xaml如下:

<Window
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:Wpf_USB"
        xmlns:hc="https://handyorg.github.io/handycontrol" x:Class="Wpf_USB.MainWindow"
        mc:Ignorable="d"
        Title="WPF_USB" Height="480" Width="800" ResizeMode="CanMinimize">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="160*"/>
            <ColumnDefinition Width="160*"/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="60*"/>
            <RowDefinition Height="60*"/>
            <RowDefinition Height="60*"/>
            <RowDefinition Height="60*"/>
        </Grid.RowDefinitions>
        <GroupBox Header="USB设备信息" BorderBrush="Black" FontSize="20" FontWeight="Bold" Margin="5,5,5,5" Grid.RowSpan="2">
            <StackPanel>
                <StackPanel Orientation="Horizontal">
                    <TextBlock TextWrapping="Wrap" Text="VendorID:" Width="auto"  RenderTransformOrigin="0.478,1.336" Padding="0,10,0,0" Height="44" Margin="10"/>
                    <ComboBox Width="177" Margin="15,10,5,10" ItemsSource="{Binding UsbPar.VendorID}" SelectedItem="{Binding CuPar.VendorID}" IsEnabled="{Binding CuPar.EnableSelect}"/>
                </StackPanel>
                <StackPanel Orientation="Horizontal">
                    <TextBlock TextWrapping="Wrap" Text="ProductID:" Width="auto" RenderTransformOrigin="0.478,1.336" Padding="0,10,0,0" Height="44" Margin="10"/>
                    <ComboBox Width="177" Margin="10,10,5,10" ItemsSource="{Binding UsbPar.ProductID}" SelectedItem="{Binding CuPar.ProductID}" IsEnabled="{Binding CuPar.EnableSelect}"/>
                </StackPanel>
                <StackPanel Orientation="Horizontal">
                    <Button Content="连接USB设备" Margin="20,0,10,0" FontSize="16" Height="38" Command="{Binding OpenUsbDev}"/>
                    <Button Content="断开USB设备" Margin="20,0,10,0" FontSize="16" Height="38" Command="{Binding CloseUsbDev}"/>
                </StackPanel>
            </StackPanel>
        </GroupBox>
        <GroupBox Header="USB接收数据区" FontSize="20"  FontWeight="Bold" BorderBrush="#FF7ED866" Margin="5,5,5,5" Grid.Row="2" Grid.RowSpan="2">
            <ScrollViewer VerticalScrollBarVisibility="Auto">
                <TextBox Name="ReceiveData" TextWrapping="Wrap" Text="{Binding CuPar.ReadDataString}" FontWeight="Normal" FontSize="16"/>
            </ScrollViewer>
        </GroupBox>
        <GroupBox Header="接收数据设置" FontSize="20"  FontWeight="Bold" Margin="5,5,5,5" BorderBrush="#FF5570C7" Grid.Column="1">
            <StackPanel Orientation="Horizontal">
                <TextBlock HorizontalAlignment="Left" TextWrapping="Wrap" Text="BytesRead:" Padding="0,15,0,0"/>
                <ComboBox Width="130" Height="40" ItemsSource="{Binding UsbPar.BytesRead}" SelectedItem="{Binding CuPar.BytesRead}" IsEnabled="{Binding CuPar.EnableSelect}"/>
                <Button Content="开始接收" FontSize="20" Height="58" Margin="5" Command="{Binding UsbDevRead}"/>
            </StackPanel>
        </GroupBox>
        <GroupBox Header="发送数据设置" FontSize="20"  FontWeight="Bold" Margin="5,5,5,5"  BorderBrush="#FF5D29A0" Grid.Column="1" Grid.Row="1">
            <StackPanel Orientation="Horizontal">
                <TextBlock HorizontalAlignment="Left" TextWrapping="Wrap" Text="BytesWrite:" Padding="0,15,0,0"/>
                <ComboBox Width="130" Height="40" ItemsSource="{Binding UsbPar.BytesWrite}" SelectedItem="{Binding CuPar.BytesWrite}" IsEnabled="{Binding CuPar.EnableSelect}"/>
                <Button Content="开始发送" FontSize="20" Height="58" Margin="5" Command="{Binding UsbDevWrite}"/>
            </StackPanel>
        </GroupBox>
        <GroupBox Header="USB发送数据区" FontSize="20"  FontWeight="Bold" Margin="5,5,5,5" BorderBrush="#FFA42D84" Grid.Column="1" Grid.RowSpan="2" Grid.Row="2">
            <ScrollViewer VerticalScrollBarVisibility="Auto">
                <TextBox Name="SendData" TextWrapping="Wrap" Text="{Binding CuPar.WriteData}" FontWeight="Normal" FontSize="16"/>
            </ScrollViewer>
        </GroupBox>
    </Grid>
</Window>

由于使用了开源控件库:HandyControl,因此App.xaml代码需要如下编写:

<Application x:Class="Wpf_USB.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local="clr-namespace:Wpf_USB"
             StartupUri="MainWindow.xaml">
    <Application.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="pack://application:,,,/HandyControl;component/Themes/SkinDefault.xaml" />
                <ResourceDictionary Source="pack://application:,,,/HandyControl;component/Themes/Theme.xaml" />
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Application.Resources>
</Application>

4、后台逻辑CS

后台MainWindow.xaml.cs代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Wpf_USB.ViewModels;

namespace Wpf_USB
{
    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            this.DataContext = new MainWindowViewModel();
        }
    }
}

USB各参数初始化类,即界面初始化的参数,UsbParameter.cs代码如下:

using LibUsbDotNet.Main;
using LibUsbDotNet;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;

namespace Wpf_USB.ViewModels
{
    class UsbParameter : NotificationObject
    {
        private ObservableCollection<int> vendorid = new ObservableCollection<int>() { 1234 };
        public ObservableCollection<int> VendorID 
        {
            get { return vendorid; }
            set
            {
                vendorid = value;
                this.RaisePropertyChanged("VendorID");
            }
        }

        private ObservableCollection<int> productid = new ObservableCollection<int>() { 1 };
        public ObservableCollection<int> ProductID
        {
            get { return productid; }
            set
            {
                productid = value;
                this.RaisePropertyChanged("ProductID");
            }
        }

        private ObservableCollection<int> bytesread = new ObservableCollection<int>() { 512, 1024, 2048, 4096, 8192, 16384 };
        public ObservableCollection<int> BytesRead
        {
            get { return bytesread; }
            set
            {
                bytesread = value;
                this.RaisePropertyChanged("BytesRead");
            }
        }

        private ObservableCollection<int> byteswrite = new ObservableCollection<int>() { 512, 1024, 2048, 4096, 8192, 16384 };
        public ObservableCollection<int> BytesWrite
        {
            get { return byteswrite; }
            set
            {
                byteswrite = value;
                this.RaisePropertyChanged("BytesWrite");
            }
        }
        public void UsbDeviceFind()
        {
            UsbRegDeviceList allDevices = UsbDevice.AllDevices;
            if (allDevices != null)
            {
                foreach (UsbRegistry usbRegistry in allDevices)
                {
                    VendorID.Add(usbRegistry.Vid);
                    ProductID.Add(usbRegistry.Pid);
                }
                UsbDevice.Exit();
            }
            else { MessageBox.Show("UsbDevive Not Found."); }            
        }
    }
}

USB更新数据类,CurrentParameter.cs代码如下:

using LibUsbDotNet;
using LibUsbDotNet.Main;
using System;
using System.Collections.Generic;
using System.IO.Ports;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
using System.Windows;
using System.Runtime.Remoting.Messaging;
using System.Collections.ObjectModel;
using System.Reflection;
using Wpf_USB.Models;

namespace Wpf_USB.ViewModels
{
    class CurrentParameter : NotificationObject
    {
        public CurrentParameter()
        {
            GloVar = new GlobalVariable();
            DataPro = new DataProcess();
        }
        private GlobalVariable gloVar;
        public GlobalVariable GloVar
        {
            get { return gloVar; }
            set
            {
                gloVar = value;
            }
        }
        private DataProcess dataPro;
        public DataProcess DataPro
        {
            get { return dataPro; }
            set
            {
                dataPro = value;
            }
        }
        private int vendorid;
        public int VendorID
        {
            get { return vendorid; }
            set
            {
                vendorid = value;
                this.RaisePropertyChanged("VendorID");
            }
        }

        private int productid;
        public int ProductID
        {
            get { return productid; }
            set
            {
                productid = value;
                this.RaisePropertyChanged("ProductID");
            }
        }

        private int bytesread;
        public int BytesRead
        {
            get { return bytesread; }
            set
            {
                bytesread = value;
                this.RaisePropertyChanged("BytesRead");
            }
        }

        private int byteswrite;
        public int BytesWrite
        {
            get { return byteswrite; }
            set
            {
                byteswrite = value;
                this.RaisePropertyChanged("BytesWrite");
            }
        }
        private UsbDevice usbDevice;
        private UsbEndpointReader epReader;
        private UsbEndpointWriter epWriter;
        public UsbDevice UsbDevice
        {
            get { return usbDevice; }
            set { usbDevice = value; this.RaisePropertyChanged("UsbDevice"); }
        }
        private byte[] readData;
        private string writeData;
        private string readDataString;
        private bool isOpen;
        private bool enableSelect = true;
        public bool EnableSelect
        {
            get { return enableSelect; }
            set { enableSelect = value; this.RaisePropertyChanged("EnableSelect"); }
        }
        public byte[] ReadData
        {
            get { return readData; }
            set { readData = value; this.RaisePropertyChanged("ReadData"); }
        }
        public string ReadDataString
        {
            get { return readDataString; }
            set { readDataString = value; this.RaisePropertyChanged("ReadDataString"); }
        }
        public string WriteData
        {
            get { return writeData; }
            set { writeData = value; this.RaisePropertyChanged("WriteData"); }
        }

        public bool IsOpen
        {
            get { return isOpen; }
            set { isOpen = value; this.RaisePropertyChanged("IsOpen"); }
        }

        public bool UsbDevicesOpen()
        {
            if (usbDevice != null && usbDevice.IsOpen)
            {
                return UsbDevicesClose();
            }
            try
            {
                UsbDeviceFinder UsbFinder = new UsbDeviceFinder(this.VendorID, this.ProductID);
                usbDevice = UsbDevice.OpenUsbDevice(UsbFinder);
                if (usbDevice == null) throw new Exception("Device Not Found.");
                IUsbDevice wholeUsbDevice = usbDevice as IUsbDevice;
                if (!ReferenceEquals(wholeUsbDevice, null))
                {
                    wholeUsbDevice.SetConfiguration(1);
                    wholeUsbDevice.ClaimInterface(0);
                }
                epReader = usbDevice.OpenEndpointReader(ReadEndpointID.Ep01);
                epWriter = usbDevice.OpenEndpointWriter(WriteEndpointID.Ep01);
                EnableSelect = false;
                if (usbDevice.IsOpen)
                {
                    return IsOpen = true;
                }
                else
                {
                    return IsOpen = false;
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
            return IsOpen = false;
        }
        public bool UsbDevicesClose()
        {
            try
            {
                EnableSelect = true;
                if (usbDevice == null) throw new Exception("Device Not Found.");
                else
                {
                    if (usbDevice.IsOpen)
                    {
                        IUsbDevice wholeUsbDevice = usbDevice as IUsbDevice;
                        if (!ReferenceEquals(wholeUsbDevice, null))
                        {
                            // Release interface #0.
                            wholeUsbDevice.ReleaseInterface(0);
                        }
                        usbDevice.Close();
                        return IsOpen = false;
                    }
                    usbDevice = null;
                    UsbDevice.Exit();
                    return IsOpen = false;
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
                return IsOpen = false;
            }
        }
        public void UsbDevicesRead()
        {
            try 
            {
                if (usbDevice == null) throw new Exception("Device Not Found.");
                else
                {
                    int bytesReadCount = BytesRead;
                    readData = new byte[bytesReadCount];
                    ErrorCode ec = epReader.Read(ReadData, 2000, out bytesReadCount);
                    this.DataPro.ReadDataCRC(ReadData);
                    ReadDataString += GloVar.CMD_H.ToString("X2") + " ";
                    ReadDataString += GloVar.CMD_L.ToString("X2") + " ";
                    ReadDataString += GloVar.RESULT_F.ToString("X2") + " ";
                    for (int i = 0; i < GloVar.ReadValidData.Length; i++)
                        ReadDataString += GloVar.ReadValidData[i].ToString("X2") + " ";
                    if (bytesReadCount == 0) MessageBox.Show("No More Bytes.");
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }
        public void UsbDevicesWrite()
        {
            try 
            {
                if (usbDevice == null) throw new Exception("Device Not Found.");
                else
                {
                    if (!String.IsNullOrEmpty(WriteData))
                    {
                        int bytesWriteCount = BytesWrite;
                        DataPro.WriteDataCRC(WriteData);
                        ErrorCode ec = epWriter.Write(GloVar.WriteValidData, 2000, out bytesWriteCount);
                        if (ec != ErrorCode.None) MessageBox.Show("Write Fail.");
                    }
                    else
                    {
                        MessageBox.Show("WriteData Is Empty.");
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }
    }
}

响应数据实时更新类,NotificationObject.cs代码如下:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Wpf_USB.ViewModels
{
    class NotificationObject : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        public void RaisePropertyChanged(string propertyName)
        {
            if (this.PropertyChanged != null)
            {
                this.PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }
}

按键命令类,DelegateCommand.cs代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;

namespace Wpf_USB.ViewModels
{
    class DelegateCommand : ICommand
    {
        public bool CanExecute(object parameter)
        {
            if (CanExecuteFunc == null)
                return true;
            return this.CanExecuteFunc(parameter);
        }

        public event EventHandler CanExecuteChanged;

        public void Execute(object parameter)
        {
            if (ExecuteAction == null)
            {
                return;
            }
            this.ExecuteAction(parameter);
        }

        public Action<object> ExecuteAction { get; set; }
        public Func<object, bool> CanExecuteFunc { get; set; }
    }
}

MainWindowViewModel.cs代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Wpf_USB.ViewModels
{
    class MainWindowViewModel : NotificationObject
    {
        public MainWindowViewModel()
        {
            UsbPar = new UsbParameter();
            CuPar = new CurrentParameter();
            this.UsbPar.UsbDeviceFind();
            CuPar.VendorID = UsbPar.VendorID[0];
            CuPar.ProductID = UsbPar.ProductID[0];
            CuPar.BytesRead = UsbPar.BytesRead[3];
            CuPar.BytesWrite = UsbPar.BytesWrite[3];
            

            this.OpenUsbDev = new DelegateCommand();
            this.OpenUsbDev.ExecuteAction = new Action<object>(this.OpenUsb);
            this.CloseUsbDev = new DelegateCommand();
            this.CloseUsbDev.ExecuteAction = new Action<object>(this.CloseUsb);
            this.UsbDevRead = new DelegateCommand();
            this.UsbDevRead.ExecuteAction = new Action<object>(this.UsbRead);
            this.UsbDevWrite = new DelegateCommand();
            this.UsbDevWrite.ExecuteAction = new Action<object>(this.UsbWrite);
        }

        private UsbParameter usbPar;
        public UsbParameter UsbPar
        {
            get { return usbPar; }
            set
            {
                usbPar = value;
                this.RaisePropertyChanged("UsbPar");
            }
        }
        private CurrentParameter cuPar;
        public CurrentParameter CuPar
        {
            get { return cuPar; }
            set
            {
                cuPar = value;
                this.RaisePropertyChanged("CuPar");
            }
        }
        public DelegateCommand OpenUsbDev { get; set; }
        private void OpenUsb(object parameter)
        {
            this.CuPar.UsbDevicesOpen();
        }
        public DelegateCommand CloseUsbDev { get; set; }
        private void CloseUsb(object parameter)
        {
            this.CuPar.UsbDevicesClose();
        }
        public DelegateCommand UsbDevRead { get; set; }
        private void UsbRead(object parameter)
        { 
            this.CuPar.UsbDevicesRead(); 
        }
        public DelegateCommand UsbDevWrite { get; set; }
        private void UsbWrite(object parameter)
        { 
            this.CuPar.UsbDevicesWrite();
        }
    }
}

数据处理类,包括自定义的通信协议,DataProcess.cs代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using Wpf_USB.ViewModels;

namespace Wpf_USB.Models
{
    class DataProcess : NotificationObject
    {
        public DataProcess() 
        {
            GloVar = new GlobalVariable();
        }

        private GlobalVariable gloVar;
        public GlobalVariable GloVar
        {
            get { return gloVar; }
            set
            {
                gloVar = value;
                this.RaisePropertyChanged("GloVar");
            }
        }

        public void ReadDataCRC(byte[] ReadData)
        {
            int CheckoutSum = 0;
            int DataLength = ReadData[2] * 256 + ReadData[3];
            if (ReadData[0].ToString("X") != "7E" || ReadData[1].ToString("X") != "7E")
            {
                GloVar.FrameData_F = true;
                MessageBox.Show("Data Frame Header Error.");
            }
            for (int i=0; i< DataLength; i++)
            {
                CheckoutSum += ReadData[i + 4];
            }
            if (Convert.ToByte(CheckoutSum & 0xFF) != Convert.ToByte(ReadData[DataLength+4]))
            {
                GloVar.FrameData_F = true;
                MessageBox.Show("Data Frame Check Error.");
            }
            GloVar.CMD_H = ReadData[4];
            GloVar.CMD_L = ReadData[5];
            GloVar.RESULT_F = ReadData[6];
            GloVar.ReadValidData = new byte[DataLength-3];
            for (int i = 0; i < (DataLength-3); i++)
            {
                GloVar.ReadValidData[i] = ReadData[i+7];
            }
            if (ReadData[DataLength + 5].ToString("X") != "45" || ReadData[DataLength + 6].ToString("X") != "4E" || ReadData[DataLength + 7].ToString("X") != "44")
            {
                GloVar.FrameData_F = true;
                MessageBox.Show("Data Frame End Error.");
            }
        }

        public void WriteDataCRC(string WriteData)
        {
            int CheckoutSum = 0 ;
            string WriteDataHex = WriteData.Replace(" ", "");
            WriteDataHex += WriteDataHex.Length % 2 != 0 ? "0" : "";
            int WriteValidDataLength = WriteDataHex.Length / 2;
            GloVar.WriteValidData = new byte[WriteValidDataLength+8];
            GloVar.WriteValidData[0] = 0x7E;
            GloVar.WriteValidData[1] = 0x7E;
            GloVar.WriteValidData[2] = Convert.ToByte((WriteValidDataLength >> 8) & 0xFF);
            GloVar.WriteValidData[3] = Convert.ToByte(WriteValidDataLength & 0xFF);
            for (int i=0; i<WriteValidDataLength; i++)
            {
                GloVar.WriteValidData[4+i] = Convert.ToByte(WriteDataHex.Substring(i * 2, 2), 16);
                CheckoutSum += GloVar.WriteValidData[4+i];
            }
            GloVar.WriteValidData[4 + WriteValidDataLength] = Convert.ToByte(CheckoutSum & 0xFF);
            GloVar.WriteValidData[5 + WriteValidDataLength] = 0x45;
            GloVar.WriteValidData[6 + WriteValidDataLength] = 0x4E;
            GloVar.WriteValidData[7 + WriteValidDataLength] = 0x44;
        }
    }
}

全局变量类,GlobalVariable.cs代码如下:

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Wpf_USB.ViewModels;

namespace Wpf_USB.Models
{
    class GlobalVariable : NotificationObject
    {
        private string globalSystemVersion = "1.0.0";
        public string GlobalSystemVersion
        {
            get { return globalSystemVersion; }
            set
            {
                globalSystemVersion = value;
                this.RaisePropertyChanged("GlobalSystemVersion");
            }
        }
        private string globalUpdateTime = "2023.7.27";
        public string GlobalUpdateTime
        {
            get { return globalUpdateTime; }
            set
            {
                globalUpdateTime = value;
                this.RaisePropertyChanged("GlobalUpdateTime");
            }
        }
        private static int cMD_H;
        public int CMD_H
        {
            get { return cMD_H; }
            set
            {
                cMD_H = value;
                this.RaisePropertyChanged("CMD_H");
            }
        }
        private static int cMD_L;
        public int CMD_L
        {
            get { return cMD_L; }
            set
            {
                cMD_L = value;
                this.RaisePropertyChanged("CMD_L");
            }
        }
        private static int rESULT_F;
        public int RESULT_F
        {
            get { return rESULT_F; }
            set
            {
                rESULT_F = value;
                this.RaisePropertyChanged("RESULT_F");
            }
        }
        public static byte[] readValidData;
        public byte[] ReadValidData
        {
            get { return readValidData; }
            set
            {
                readValidData = value;
                this.RaisePropertyChanged("ReadValidData");
            }
        }
        public static byte[] writeValidData;
        public byte[] WriteValidData
        {
            get { return writeValidData; }
            set
            {
                writeValidData = value;
                this.RaisePropertyChanged("WriteValidData");
            }
        }
        public static bool frameData_F = false;
        public bool FrameData_F
        {
            get { return frameData_F; }
            set
            {
                frameData_F = value;
                this.RaisePropertyChanged("FrameData_F");
            }
        }
    }
}

该Demo实现过程中,参考了一些大佬(CSDN和Github)的代码,在此表示感谢

希望本文对大家有帮助,上文若有不妥之处,欢迎指正

分享决定高度,学习拉开差距

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/799214.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

在线帮助文档——帮助客户快速了解您的产品如何使用

当新接触到一个产品或者软件&#xff0c;在使用上遇到问题时&#xff0c;以往第一件事就是给咨询客服人员或者打电话等形式&#xff0c;每天客服人员都需要回答很多同样的问题&#xff0c;长期下去&#xff0c;客服人员压力大&#xff0c;离职率高&#xff0c;并且人工客服在这…

瓴羊Quick BI:可视化大屏界面设计满足企业个性需求

大数据技术成为现阶段企业缩短与竞争对手之间差距的重要抓手&#xff0c;依托以瓴羊Quick BI为代表的工具开展内部数据处理分析工作&#xff0c;也成为诸多企业持续获取竞争优势的必由之路。早年间国内企业倾向于使用进口BI工具&#xff0c;但随着瓴羊Quick BI等一众国内数据处…

从零开始学习CTF——CTF是什么

引言&#xff1a; 从2019年10月开始接触CTF&#xff0c;学习了sql注入、文件包含等web知识点&#xff0c;但都是只知道知识点却实用不上&#xff0c;后来在刷CTF题才发现知识点的使用方法&#xff0c;知道在哪里使用&#xff0c;哪里容易出漏洞&#xff0c;可是在挖src漏洞中还…

勘探开发人工智能应用:测井岩相识别

1 测井岩相识别 1.1 简介 岩相识别是最基础的工作,能够获得地层岩石物理特性的直观认识,进而帮助实时钻井、地质评价和储层建模。 地球物理测井使用特定的设备,观测井眼内不同深度地层的声学特性、电学特性、放射性、热力学特性等地球物理特性。通过确定地球物理测井采集的…

前端面试题 —— Vue (二)

目录 一、过滤器的作用&#xff0c;如何实现一个过滤器 二、v-model 是如何实现的&#xff0c;语法糖实际是什么&#xff1f; 三、$nextTick 原理及作用 四、Vue 中给 data 中的对象属性添加一个新的属性时会发生什么&#xff1f;如何解决&#xff1f; 五、简述 mixin、ex…

【C++进阶】:多态

多态 一.概念二.多态的定义和实现1.简单使用2.虚函数重写的两个例外1.协变2.析构函数的重写 3. C11 override 和 final4.重载&#xff0c;重定义&#xff0c;重写对比 三.多态的原理1.虚函数表2.总结3.静态绑定和动态绑定 四.单继承和多继承1.单继承2.多继承1.多继承的虚表2.多…

【代码随想录day21】二叉树的最近公共祖先

题目 给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。 百度百科中最近公共祖先的定义为&#xff1a;“对于有根树 T 的两个节点 p、q&#xff0c;最近公共祖先表示为一个节点 x&#xff0c;满足 x 是 p、q 的祖先且 x 的深度尽可能大&#xff08;一个节点也可以是它…

java对象的强引用,弱引用,软引用,虚引用

前言:java对象在java虚拟机中的生存状态&#xff0c;面试可能会有人问道&#xff0c;了解一下 这里大量引用 《疯狂Java讲义第4版》 书中的内容

基于SpringBoot+Vue的家政服务管理平台设计与实现(源码+LW+部署文档等)

博主介绍&#xff1a; 大家好&#xff0c;我是一名在Java圈混迹十余年的程序员&#xff0c;精通Java编程语言&#xff0c;同时也熟练掌握微信小程序、Python和Android等技术&#xff0c;能够为大家提供全方位的技术支持和交流。 我擅长在JavaWeb、SSH、SSM、SpringBoot等框架…

h3c irf简单配置案例

配置以双线连接为例&#xff0c;注意配置步骤不能颠倒。 SW1配置&#xff1a; 1.将设备优先级调整为32&#xff08;1-32&#xff09;&#xff0c;确保该设备被选举为Master&#xff08;主设备&#xff09; [SW1]irf member 1 priority 32 2.关闭要加入的IRF的物理端口。 [SW1…

基于Web的智慧景区GIS三维可视化运营系统

随着人民生活水平的提高和旅游产品的丰富多样&#xff0c;我国人民对于旅游的需求逐渐从“走过场”转变为“品质体验”。 建设背景 随着互联网、大数据、人工智能等新技术在旅游领域的应用&#xff0c;以数字化、网络化、智能化为特征的智慧旅游成为旅游业高质量发展新动能。…

【css】小众

纯CSS实现四种方式文本反差色效果 mix-blend-mode: difference; clip-path&#xff1b; background-clip: text, padding-box outline 是绘制于元素周围的一条线&#xff0c;位于边框边缘的外围&#xff0c;可起到突出元素的作用。 css 样式之 filter 滤镜属性 用法与示例 使…

OpenGL Metal Shader 编程:解决图片拉伸变形问题

前面发了一些关于 Shader 编程的文章&#xff0c;有读者反馈太碎片化了&#xff0c;希望这里能整理出来一个系列&#xff0c;方便系统的学习一下 Shader 编程。 由于主流的 Shader 编程网站&#xff0c;如 ShaderToy, gl-transitions 都是基于 GLSL 开发 Shader &#xff0c;加…

基于深度学习的CCPD车牌检测系统(PyTorch+Pyside6+YOLOv5模型)

摘要&#xff1a;基于CCPD数据集的高精度车牌检测系统可用于日常生活中检测与定位车牌目标&#xff0c;利用深度学习算法可实现图片、视频、摄像头等方式的车牌目标检测识别&#xff0c;另外支持结果可视化与图片或视频检测结果的导出。本系统采用YOLOv5目标检测模型训练数据集…

单机部署NGINX

​ 1、找到合适的nginx资源包&#xff0c;可以去官网下载 这里用的是 nginx-1.24.0.tar.gz 2、上传下载下来的nginx软件包&#xff0c;并解压 tar zxvf nginx-1.24.0.tar.gz cd nginx-1.24.0/ 3、安装nginx 编译 ./configure --prefix/usr/local/nginx --with-http_ssl…

从Vue2到Vue3【六】——Vue3的改变(文末送书)

系列文章目录 内容链接从Vue2到Vue3【零】Vue3简介从Vue2到Vue3【一】Composition API&#xff08;第一章&#xff09;从Vue2到Vue3【二】Composition API&#xff08;第二章&#xff09;从Vue2到Vue3【三】Composition API&#xff08;第三章&#xff09;从Vue2到Vue3【四】C…

Java面向对象的学习第二部分

接着上一部分继续&#xff1a;上一部分学了类和对象的一些基本概念、以及对象的特性之一&#xff1a;封装性。 一、面向对象 this方法补充&#xff1a; 在前面已经学了this方法&#xff0c;关于怎么使用&#xff0c;已经很属性了&#xff0c;但还是需要补充一些知识点&#xf…

Java中的代理模式

Java中的代理模式 1. 静态代理JDK动态代理CGLib动态代理 1. 静态代理 接口 public interface ICeo {void meeting(String name) throws InterruptedException; }目标类 public class Ceo implements ICeo{public void meeting(String name) throws InterruptedException {Th…

玩转回文:探索双下标法解谜,揭秘验证回文串的智慧攻略

本篇博客会讲解力扣“125. 验证回文串”的解题思路&#xff0c;这是题目链接。 验证回文串&#xff0c;我们最容易想到的思路就是&#xff0c;使用两个下标left和right&#xff0c;分别表示字符串的第一个字符和最后一个字符。接着&#xff0c;让两个下标不断向中间移动&#x…

Mysql 5.7 连接数爆满 清理连接数

Mysql 5.7 连接数爆满 清理连接数 我在做项目的时候遇到了这个报错&#xff0c;然后搜了半天也没有在网上找到mysql清理连接数的方案&#xff0c;后面还是自己写了一个 打开MySQL命令行或客户端&#xff0c;并使用管理员权限登录到MySQL服务器。 我这里使用的是navicat 输入…