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

9 篇文章 0 订阅
7 篇文章 0 订阅

1、USB调试助手Demo

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

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

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)的代码,在此表示感谢

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

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

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
好的,以下是一个简单的WPF MVVM登录DEMO的代码示例: XAML代码: ``` <Window x:Class="LoginDemo.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Login Demo" Height="250" Width="400"> <Grid> <Grid.RowDefinitions> <RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition Width="Auto"/> <ColumnDefinition Width="*"/> </Grid.ColumnDefinitions> <Label Grid.Row="0" Grid.Column="0" Content="Username:" Margin="10"/> <TextBox Grid.Row="0" Grid.Column="1" Text="{Binding Username}" Margin="10"/> <Label Grid.Row="1" Grid.Column="0" Content="Password:" Margin="10"/> <PasswordBox Grid.Row="1" Grid.Column="1" Password="{Binding Password}" Margin="10"/> <Button Grid.Row="2" Grid.Column="1" Content="Login" Command="{Binding LoginCommand}" Margin="10"/> <TextBlock Grid.Row="3" Grid.Column="1" Text="{Binding ErrorMessage}" Foreground="Red" Margin="10"/> <CheckBox Grid.Row="4" Grid.Column="1" Content="Remember me" IsChecked="{Binding RememberMe}" Margin="10"/> </Grid> </Window> ``` ViewModel代码: ``` using System; using System.ComponentModel; using System.Windows; using System.Windows.Input; namespace LoginDemo { public class LoginViewModel : INotifyPropertyChanged { private string _username; private string _password; private bool _rememberMe; private string _errorMessage; public string Username { get { return _username; } set { _username = value; OnPropertyChanged("Username"); } } public string Password { get { return _password; } set { _password = value; OnPropertyChanged("Password"); } } public bool RememberMe { get { return _rememberMe; } set { _rememberMe = value; OnPropertyChanged("RememberMe"); } } public string ErrorMessage { get { return _errorMessage; } set { _errorMessage = value; OnPropertyChanged("ErrorMessage"); } } public ICommand LoginCommand { get; set; } public LoginViewModel() { LoginCommand = new RelayCommand(Login); } private void Login(object parameter) { if (string.IsNullOrEmpty(Username) || string.IsNullOrEmpty(Password)) { ErrorMessage = "Please enter both username and password."; } else if (Username == "admin" && Password == "password") { ErrorMessage = ""; MessageBox.Show("Login successful!"); } else { ErrorMessage = "Invalid username or password."; } } public event PropertyChangedEventHandler PropertyChanged; protected virtual void OnPropertyChanged(string propertyName) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } } } ``` 其中,RelayCommand是一个自定义的ICommand实现,用于绑定按钮的Command属性,代码如下: ``` using System; using System.Windows.Input; namespace LoginDemo { public class RelayCommand : ICommand { private readonly Action<object> _execute; private readonly Predicate<object> _canExecute; public RelayCommand(Action<object> execute, Predicate<object> canExecute = null) { _execute = execute ?? throw new ArgumentNullException(nameof(execute)); _canExecute = canExecute; } public bool CanExecute(object parameter) { return _canExecute?.Invoke(parameter) ?? true; } public void Execute(object parameter) { _execute(parameter); } public event EventHandler CanExecuteChanged { add { CommandManager.RequerySuggested += value; } remove { CommandManager.RequerySuggested -= value; } } } } ``` 在MainWindow的构造函数中,将ViewModel与View绑定: ``` public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); DataContext = new LoginViewModel(); } } ``` 这样,就完成了一个简单的WPF MVVM登录DEMO

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

鲁棒最小二乘支持向量机

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值