news 2026/5/12 18:59:10

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/5/7 17:58:28

电商运营中的数据驱动的决策流程

电商运营中的数据驱动的决策流程关键词&#xff1a;电商运营、数据驱动、决策流程、数据分析、商业智能摘要&#xff1a;本文围绕电商运营中数据驱动的决策流程展开深入探讨。首先介绍了该主题的背景&#xff0c;包括目的、预期读者、文档结构和相关术语。接着阐述了核心概念及…

作者头像 李华
网站建设 2026/5/12 16:39:17

vitis安装目录结构解析:深入理解集成环境布局

深入Vitis安装目录&#xff1a;一张嵌入式开发的“藏宝图”你有没有遇到过这样的场景&#xff1f;刚接手一个Zynq项目&#xff0c;同事丢给你一句&#xff1a;“XSA文件在platforms/里”&#xff0c;你打开Vitis却不知道从哪找&#xff1b;或者CI流水线突然报错“找不到aarch64…

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

调试UART中断异常的五大核心要点总结

一次UART中断异常排查的深度复盘&#xff1a;从数据丢失到系统稳定的五大实战要点最近在调试一款工业网关设备时&#xff0c;遇到了一个典型的“UART接收中断突然停止响应”的问题。现象很诡异&#xff1a;上电初期通信正常&#xff0c;但运行几分钟后&#xff0c;某个串口的数…

作者头像 李华
网站建设 2026/5/2 16:20:53

一加15一加Ace6等等机型一键root解锁bl教程

微信公众号&#xff1a;宝藏树首先安装深度测试app申请审核通过&#xff0c;再进行以下操作首先&#xff1a;手机打开设置/关于手机/版本信息&#xff0c;版本号 连续点击7次 返回设置 搜索开发者选项&#xff0c;进入开发者-OEM解锁打开-USB调试打开&#xff0c;手机有弹窗…

作者头像 李华
网站建设 2026/5/12 17:30:37

电感的作用核心要点:自感与互感的实际影响

电感的“看不见”的力量&#xff1a;从自感到互感&#xff0c;拆解它如何掌控电路的能量与信号你有没有遇到过这样的情况&#xff1f;一个开关电源莫名其妙地烧了MOS管&#xff0c;查来查去发现是变压器初级的一个反峰电压击穿了器件&#xff1b;或者在高速数字板上&#xff0c…

作者头像 李华