news 2026/6/15 13:06:55

WPF实现Modbus TCP通信客户端

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
WPF实现Modbus TCP通信客户端

一、概述:

使用:WPF、+ MVVM
Prism.DryIoc、system.IO.Ports、NMmodbus4

二、架构:

  • Views

    • MainWindow.xaml

  • Models

    • ModbusClient

  • ViewModels

    • MainWindowViewModel

  • Services

    • Interface

      • IModbusService

    • ModbusService

三、ModbusClient

public class ModbusClient { public ushort Address { get; set; } public ushort Value { get; set; } public string DisplayText => $"Addr {Address}: {Value}"; }

四、IModbusService

public interface IModbusService { Task<bool> ConnectAsync(string ipAddress, int port); Task<ushort[]> ReadHoldingRegistersAsync(ushort startAddress, ushort numberOfPoints); Task<bool> WriteSingleRegisterAsync(ushort address, ushort value); void Disconnect(); bool IsConnected { get; } }

五、ModbusService

public class ModbusService : IModbusService { private TcpClient? _tcpClient; private ModbusIpMaster? _master; public bool IsConnected => _tcpClient?.Connected == true && _master != null; public async Task<bool> ConnectAsync(string ipAddress, int port) { try { _tcpClient = new TcpClient(); await _tcpClient.ConnectAsync(ipAddress, port); if (!_tcpClient.Connected) return false; _master = ModbusIpMaster.CreateIp(_tcpClient); return true; } catch { Disconnect(); return false; } } public async Task<ushort[]> ReadHoldingRegistersAsync(ushort startAddress, ushort numberOfPoints) { if (!IsConnected || _master == null) throw new InvalidOperationException("Not connected to Modbus server."); return await Task.Run(() => _master.ReadHoldingRegisters(0, startAddress, numberOfPoints)); } public async Task<bool> WriteSingleRegisterAsync(ushort address, ushort value) { if (!IsConnected || _master == null) return false; await Task.Run(() => _master.WriteSingleRegister(0, address, value)); return true; } public void Disconnect() { _master?.Dispose(); _tcpClient?.Close(); _tcpClient?.Dispose(); _master = null; _tcpClient = null; } }

六、MainWindowViewModel

public class MainWindowViewModel : BindableBase { private readonly IModbusService _modbusService; private string _ipAddress = "127.0.0.1"; private int _port = 502; private ushort _startAddress = 0; private ushort _count = 10; private string _status = "Disconnected"; private ObservableCollection<ModbusClient> _modbusClient = new(); public string IpAddress { get => _ipAddress; set => SetProperty(ref _ipAddress, value); } public int Port { get => _port; set => SetProperty(ref _port, value); } public ushort StartAddress { get => _startAddress; set => SetProperty(ref _startAddress, value); } public ushort Count { get => _count; set => SetProperty(ref _count, value); } public string Status { get => _status; set => SetProperty(ref _status, value); } public ObservableCollection<ModbusClient> modbusClient { get => _modbusClient; set => SetProperty(ref _modbusClient, value); } public DelegateCommand ConnectCommand { get; } public DelegateCommand DisconnectCommand { get; } public DelegateCommand ReadRegistersCommand { get; } public MainWindowViewModel(IModbusService modbusService) { _modbusService = modbusService; ConnectCommand = new DelegateCommand(Connect); DisconnectCommand = new DelegateCommand(Disconnect); ReadRegistersCommand = new DelegateCommand(ReadRegisters); } private async void Connect() { var success = await _modbusService.ConnectAsync(IpAddress, Port); Status = success ? "Connected" : "Connection failed"; } private void Disconnect() { _modbusService.Disconnect(); Status = "Disconnected"; } private async void ReadRegisters() { try { var data = await _modbusService.ReadHoldingRegistersAsync(StartAddress, Count); modbusClient.Clear(); for (int i = 0; i < data.Length; i++) { modbusClient.Add(new ModbusClient { Address = (ushort)(StartAddress + i), Value = data[i], }); } } catch (Exception ex) { MessageBox.Show($"Error reading registers: {ex.Message}"); } } }

七、MainWindow.xaml

<Window x:Class="ModbusDemo.Views.MainWindow" 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:ModbusDemo" mc:Ignorable="d" Title="Modbus TCP Client" Height="450" Width="800"> <Grid Margin="10"> <Grid.RowDefinitions> <RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/> <RowDefinition Height="*"/> </Grid.RowDefinitions> <!-- Connection Panel --> <StackPanel Orientation="Horizontal" Margin="0,0,0,10"> <TextBox Text="{Binding IpAddress}" Width="120" Margin="0,0,5,0"/> <TextBox Text="{Binding Port}" Width="60" Margin="0,0,10,0"/> <Button Content="Connect" Command="{Binding ConnectCommand}" Width="80" Margin="0,0,5,0"/> <Button Content="Disconnect" Command="{Binding DisconnectCommand}" Width="80"/> </StackPanel> <!-- Status --> <TextBlock Grid.Row="1" Text="{Binding Status}" Margin="0,0,0,10"/> <!-- Read Panel --> <StackPanel Grid.Row="2" Orientation="Horizontal" VerticalAlignment="Top"> <TextBox Text="{Binding StartAddress}" Width="60" Margin="0,0,5,0"/> <TextBox Text="{Binding Count}" Width="50" Margin="0,0,10,0"/> <Button Content="Read Holding Registers" Command="{Binding ReadRegistersCommand}"/> </StackPanel> <!-- Register List --> <ListBox Grid.Row="2" Margin="0,40,0,0" ItemsSource="{Binding modbusClient}" > <ListBox.ItemTemplate> <DataTemplate> <StackPanel Orientation="Horizontal"> <TextBlock Text="{Binding Address, StringFormat='Addr {0}: '}" FontWeight="Bold"/> <TextBlock Text="{Binding Value}"/> <TextBlock Text="{Binding DisplayText}" Margin="30 0"/> </StackPanel> </DataTemplate> </ListBox.ItemTemplate> </ListBox> </Grid> </Window>

八、MainWindow.xaml.cs

namespace ModbusDemo.Views { /// <summary> /// Interaction logic for MainWindow.xaml /// </summary> public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } } }

九、App.xaml

<prism:PrismApplication x:Class="ModbusDemo.App" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:ModbusDemo" xmlns:prism="http://prismlibrary.com/"> <Application.Resources> </Application.Resources> </prism:PrismApplication>

十、App.xaml.cs

using ModbusDemo.Services.Interface; using ModbusDemo.Services; using ModbusDemo.Views; using System.Windows; using ModbusDemo.ViewModels; namespace ModbusDemo { /// <summary> /// Interaction logic for App.xaml /// </summary> public partial class App : PrismApplication { protected override Window CreateShell() { return Container.Resolve<MainWindow>(); } protected override void RegisterTypes(IContainerRegistry containerRegistry) { containerRegistry.RegisterSingleton<IModbusService, ModbusService>(); containerRegistry.RegisterForNavigation<MainWindow, MainWindowViewModel>(); } } }
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/6 1:57:31

新手教程:如何正确完成libwebkit2gtk-4.1-0安装配置

如何在 Linux 上正确安装并配置 libwebkit2gtk-4.1&#xff1a;从踩坑到实战你是不是也遇到过这种情况&#xff1f;刚写好一个基于 GTK 的浏览器小程序&#xff0c;兴冲冲地编译运行&#xff0c;结果终端弹出一行红色错误&#xff1a;error while loading shared libraries: li…

作者头像 李华
网站建设 2026/6/13 16:36:16

USB接口有几种?图文详解主流类型

USB接口有几种&#xff1f;从“插不准”到“一线通”的演进之路 你有没有过这样的经历&#xff1a;手机没电了&#xff0c;急着充电&#xff0c;可那根USB线就是“死活插不进去”&#xff1f;翻来覆去试了三次&#xff0c;才对准方向——别怀疑自己&#xff0c;这正是 传统USB…

作者头像 李华
网站建设 2026/6/10 10:31:59

通信协议入门:rs232和rs485的区别全面讲解

从调试口到工业总线&#xff1a;RS232与RS485的本质差异与实战选型指南你有没有遇到过这样的场景&#xff1f;一台设备通过串口连不上PC&#xff0c;换根线就好了&#xff1b;或者在工厂里布了一圈RS485总线&#xff0c;结果数据乱跳、通信时断时续。更头疼的是&#xff0c;明明…

作者头像 李华
网站建设 2026/6/9 21:37:52

电车顶不住,涨价卖车,但外资油车降价狙击,进退失据!

2026刚开始部分电车企业的中低端车型已悄然涨价&#xff0c;显然他们无法承受补贴减少和购置税减半征收带来成本压力&#xff0c;而选择悄悄涨价&#xff0c;可是外资油车却不让他们喘息&#xff0c;率先降价反击&#xff0c;这让电车陷入两难境地。电车对于中低端车型悄然涨价…

作者头像 李华
网站建设 2026/5/20 3:36:49

4位全加器实验常见问题排查与数码管调试技巧

4位全加器联调实战&#xff1a;从电路搭建到数码管显示的完整排错指南 你有没有遇到过这种情况——逻辑设计明明无懈可击&#xff0c;Verilog代码仿真波形完美&#xff0c;结果一接到七段数码管上&#xff0c;显示出来的却是“8”变成“3”&#xff0c;或者“00”居然亮了两个数…

作者头像 李华
网站建设 2026/6/10 17:21:25

基于Java+SpringBoot+SSM动漫分享系统(源码+LW+调试文档+讲解等)/动漫交流平台/动漫资源分享/动漫社区系统/动漫分享网站/动漫共享平台

博主介绍 &#x1f497;博主介绍&#xff1a;✌全栈领域优质创作者&#xff0c;专注于Java、小程序、Python技术领域和计算机毕业项目实战✌&#x1f497; &#x1f447;&#x1f3fb; 精彩专栏 推荐订阅&#x1f447;&#x1f3fb; 2025-2026年最新1000个热门Java毕业设计选题…

作者头像 李华