C#上位机与欧姆龙PLC的通信10----开发专用的通讯工具软件(WPF版)

1、介绍

上节开发了一个winform版的通讯测试工具,这节再搞个wpf版的,wpf是什么?请自行百度,也可以看前面的博客,WPF真入门教程,wpf的界面效果是比winform漂亮,因为wpf使用了web项目中的css样式来美化界面,在这个例子中用到wpf的控件,资源样式,命令绑定等,采用的是mvvm的渲染模式,界面如图:

前面的winform界面:

 2、开工干

2.1 创建wpf项目

2.2 创建目录及PLC模型类对象

 2.3 创建自定义的消息弹窗

MsgBoxWindow.xaml代码

<Window x:Class="OmronFinsWPFApp.MsgBoxWindow"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:OmronFinsWPFApp"mc:Ignorable="d"Title="消息框" Height="200" Width="420" WindowStartupLocation="CenterScreen" BorderThickness="1,0,1,1" ResizeMode="NoResize" WindowStyle="None" AllowsTransparency="True" Background="Transparent"><Window.Resources><Style TargetType="Button" x:Key="msgbtnStyle"><Setter Property="Width" Value="60"/><Setter Property="Height" Value="25"/><Setter Property="Margin" Value="10,0,15,0"/></Style></Window.Resources><Grid Background="Transparent" MouseLeftButtonDown="Grid_MouseLeftButtonDown" ><Border BorderBrush="#FFA9AEB1"  BorderThickness="2" CornerRadius="10" Margin="5"><Border.Effect><DropShadowEffect BlurRadius="10" Color="#FFB8BBC8" Direction="300" ShadowDepth="2"/></Border.Effect><Border.Background><LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0"><GradientStop Color="#FFFBFBFB" Offset="0.16"/><GradientStop Color="#FFB4D8E2" Offset="0.986"/></LinearGradientBrush></Border.Background><Grid x:Name="grid" Margin="5"><Grid.RowDefinitions><RowDefinition Height="30"/><RowDefinition/><RowDefinition Height="50" /></Grid.RowDefinitions><Grid Grid.Row="0" Background="Transparent"><Border  Background="Transparent"  ><Grid><TextBlock Text="{Binding MessageTitle}" HorizontalAlignment="Left"  Height="25" Width="200" VerticalAlignment="Center" Margin="5,0" /><Image Source="imgs/errbtn.jpg" HorizontalAlignment="Right" Margin="0,3,3,2"  MouseLeftButtonDown="Image_MouseLeftButtonDown"/></Grid></Border></Grid><!--显示图片和文本--><StackPanel Grid.Row="1" VerticalAlignment="Center" Orientation="Horizontal"><Image Source="{Binding ImagePath}" Width="30" Height="30" Margin="40,20,20,20"/><TextBlock VerticalAlignment="Center" HorizontalAlignment="Left" TextWrapping="WrapWithOverflow" Width="280" TextAlignment="Left"Text="{Binding MessageBoxText}" FontSize="12"/></StackPanel><!--Button Margin(坐上右下)--><StackPanel Grid.Row="2" Orientation="Horizontal" HorizontalAlignment="Right"><Button Content="确 定" Style="{StaticResource msgbtnStyle}" x:Name="OkButton"   IsDefault="True"Visibility="{Binding OkButtonVisibility,Mode=OneWay}" Click="OkButton_Click"/><Button Content="是" Style="{StaticResource msgbtnStyle}"  x:Name="YesButton"  Visibility="{Binding YesButtonVisibility,Mode=OneWay}" Click="YesButton_Click"/><Button Content="否" Style="{StaticResource msgbtnStyle}"  x:Name="NoButton" Visibility="{Binding NoButtonVisibility,Mode=OneWay}" Click="NoButton_Click"/><Button Content="取消" Style="{StaticResource msgbtnStyle}"  x:Name="CancelButton" Visibility="{Binding CancelButtonVisibility}" Click="CancelButton_Click"/></StackPanel></Grid></Border></Grid>
</Window>

 MsgBoxWindow.xaml.cs代码(这是页面MsgBoxWindow.xaml的后台逻辑代码)

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.Shapes;namespace OmronFinsWPFApp
{/// <summary>/// MsgBoxWindow.xaml 的交互逻辑/// </summary>public partial class MsgBoxWindow : Window{public MsgBoxWindow(){InitializeComponent();this.DataContext = this;//所有按钮不显示()OkButtonVisibility = Visibility.Collapsed;CancelButtonVisibility = Visibility.Collapsed;YesButtonVisibility = Visibility.Collapsed;NoButtonVisibility = Visibility.Collapsed;Result = CustomMessageBoxResult.None;}/// <summary>/// 显示按钮类型/// </summary>public enum CustomMessageBoxButton{OK = 1,OKCancel = 2,YesNo = 3,YesNoCancel = 4}/// <summary>/// 消息框返回值/// </summary>public enum CustomMessageBoxResult{None = 0,//用户直接关闭消息框OK = 1,//用户点击了确定按钮Cancel = 2,//用户点击了取消按钮Yes = 3,//用户点击了是按钮No = 4//用户点击了否按钮}/// <summary>/// 图标类型/// </summary>public enum CustomMessageBoxIcon{None = 0,Error = 1,Question = 2,Infomation = 3}#region 页面属性定义/// <summary>/// 消息文本/// </summary>public string MessageBoxText { get; set; }/// <summary>/// 消息框标题/// </summary>public string MessageTitle { get; set; }/// <summary>/// 图标路径/// </summary>public string ImagePath { get; set; }/// <summary>/// 显示确定/// </summary>public Visibility OkButtonVisibility { get; set; }/// <summary>/// 显示取消/// </summary>public Visibility CancelButtonVisibility { get; set; }/// <summary>/// 显示是/// </summary>public Visibility YesButtonVisibility { get; set; }/// <summary>/// 显示否/// </summary>public Visibility NoButtonVisibility { get; set; }/// <summary>/// 消息框返回值/// </summary>public CustomMessageBoxResult Result { get; set; }#endregionprivate void CancelButton_Click(object sender, RoutedEventArgs e){Result = CustomMessageBoxResult.Cancel;this.Close();}private void NoButton_Click(object sender, RoutedEventArgs e){Result = CustomMessageBoxResult.No;this.Close();}private void YesButton_Click(object sender, RoutedEventArgs e){Result = CustomMessageBoxResult.Yes;this.Close();}private void OkButton_Click(object sender, RoutedEventArgs e){Result = CustomMessageBoxResult.OK;this.Close();}private void Image_MouseLeftButtonDown(object sender, MouseButtonEventArgs e){this.Close();}/// <summary>/// 消息框拖动/// </summary>/// <param name="sender"></param>/// <param name="e"></param>private void Grid_MouseLeftButtonDown(object sender, MouseButtonEventArgs e){this.DragMove();}/// <summary>/// 显示消息框/// </summary>/// <param name="msgText"></param>/// <param name="title"></param>/// <param name="msgBtn"></param>/// <param name="msgIcon"></param>/// <returns></returns>public static CustomMessageBoxResult Show(string msgText, string title, CustomMessageBoxButton msgBtn, CustomMessageBoxIcon msgIcon){MsgBoxWindow msg = new MsgBoxWindow();msg.Topmost = true;msg.MessageBoxText = msgText;msg.MessageTitle = title;//消息框按钮显示switch (msgBtn){case CustomMessageBoxButton.OK:msg.OkButtonVisibility = Visibility.Visible;break;case CustomMessageBoxButton.OKCancel:msg.OkButtonVisibility = Visibility.Visible;msg.CancelButtonVisibility = Visibility.Visible;break;case CustomMessageBoxButton.YesNo:msg.YesButtonVisibility = Visibility.Visible;msg.NoButtonVisibility = Visibility.Visible;break;case CustomMessageBoxButton.YesNoCancel:msg.YesButtonVisibility = Visibility.Visible;msg.NoButtonVisibility = Visibility.Visible;msg.CancelButtonVisibility = Visibility.Visible;break;default:msg.OkButtonVisibility = Visibility.Visible;break;}switch (msgIcon){case CustomMessageBoxIcon.Infomation:msg.ImagePath = @"imgs/success.jpg";break;case CustomMessageBoxIcon.Error:msg.ImagePath = @"imgs/error.jpg";break;case CustomMessageBoxIcon.Question:msg.ImagePath = @"imgs/question.jpg";break;}msg.ShowDialog();return msg.Result;} }
}

2.4 添加之前的通讯库dll文件,并引用到项目中

2.5 添加目录及命令类RelayCommand

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;namespace OmronFinsWPFApp.Common
{/// <summary>/// 命令实现类/// </summary>public class RelayCommand : ICommand{public event EventHandler CanExecuteChanged;/// <summary>/// 要执行的操作/// </summary>private Action<object> executeActions;/// <summary>/// 是否可以执行的委托/// </summary>private Func<object, bool> canExecuteFunc;/// <summary>/// 构造函数 无参构造/// </summary>public RelayCommand() { }/// <summary>/// 通过执行的委托构造/// </summary>/// <param name="execute"></param>public RelayCommand(Action<object> execute) : this(execute, null){}/// <summary>/// 通过执行的操作与是否可执行的委托/// </summary>/// <param name="execute">要执行的操作</param>/// <param name="canExecute">是否可以被执行</param>public RelayCommand(Action<object> execute, Func<object, bool> canExecute){this.executeActions = execute;this.canExecuteFunc = canExecute;}/// <summary>/// 命令是否可以执行/// </summary>/// <param name="parameter"></param>/// <returns></returns>public bool CanExecute(object parameter){if (canExecuteFunc != null)return this.canExecuteFunc(parameter);elsereturn true;}/// <summary>/// 要执行的操作/// </summary>/// <param name="parameter"></param>public void Execute(object parameter){if (executeActions == null)return;this.executeActions(parameter);}/// <summary>/// 执行CanExecuteChanged事件/// </summary>public void OnCanExecuteChanged(){this.CanExecuteChanged?.Invoke(this, new EventArgs());}}
}

2.6 添加视图模型类对象

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using static OmronFinsWPFApp.MsgBoxWindow;namespace OmronFinsWPFApp.ViewModel
{/// <summary>/// 视图模型基类/// </summary>public class ViewModelBase : INotifyPropertyChanged{/// <summary>/// 属性值发生更改时触发/// </summary>public event PropertyChangedEventHandler PropertyChanged;/// <summary>/// 执行更改/// C#5.0中的新特性CallerMemberName/// </summary>/// <param name="propertyName"></param>protected void OnPropertyChanged([CallerMemberName] string propertyName = ""){if (PropertyChanged != null){PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyName));}}/// <summary>/// 成功消息提示/// </summary>/// <param name="message"></param>/// <param name="title"></param>/// <param name="buttons"></param>public void ShowMessage(string message, string title = "提示", CustomMessageBoxButton buttons = CustomMessageBoxButton.OK){Show(message, title, buttons, CustomMessageBoxIcon.Infomation);}/// <summary>/// 错误消息框/// </summary>/// <param name="message"></param>/// <param name="title"></param>/// <param name="buttons"></param>public void ShowError(string message, string title = "错误", CustomMessageBoxButton buttons = CustomMessageBoxButton.OK){Show(message, title, buttons, CustomMessageBoxIcon.Error);}/// <summary>/// 询问消息框/// </summary>/// <param name="message"></param>/// <param name="title"></param>/// <param name="buttons"></param>/// <returns></returns>public CustomMessageBoxResult ShowQuestion(string message, string title = "询问", CustomMessageBoxButton buttons = CustomMessageBoxButton.OKCancel){return Show(message, title, buttons, CustomMessageBoxIcon.Question);}}
}

 

using Omron.Communimcation.Fins.Omron;
using OmronFinsWPFApp.Common;
using OmronFinsWPFApp.Model;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;namespace OmronFinsWPFApp.ViewModel
{/// <summary>/// 视图模型/// </summary>public class MainViewModel : ViewModelBase{/// <summary>/// finstcp对象/// </summary>FinsTcp finsTcp; PLCMemoryModel readPLCModel = SetInitModel();/// <summary>/// 读取PLC/// </summary>public PLCMemoryModel ReadPLCModel{get { return readPLCModel; }set{readPLCModel = ReadPLCModel;OnPropertyChanged();//属性通知}}PLCMemoryModel writePLCModel = SetInitModel();/// <summary>/// 写入PLC/// </summary>public PLCMemoryModel WritePLCModel{get { return writePLCModel; }set{writePLCModel = WritePLCModel;OnPropertyChanged();}}/// <summary>/// 初始化页面参数/// </summary>/// <returns></returns>private static PLCMemoryModel SetInitModel(){PLCMemoryModel model = new PLCMemoryModel();model.Area = "DM";model.DataType = "ushort";model.Address = "";model.Count = "1";return model;}private string hostName = "192.168.1.4";/// <summary>/// PLC地址/// </summary>public string HostName{get{return hostName;}set{hostName = value;}}private string hostPort = "7788";/// <summary>/// PLC端口/// </summary>public string HostPort{get { return hostPort; }set{hostPort = value;}}/// <summary>/// 存储区下拉框数据源/// </summary>public List<string> CboCustTypes{get{return new List<string>() { "DM", "H", "W", "CIO" };}}/// <summary>/// 数据类型/// </summary>public List<string> CboCustDatas{get{return new List<string>() { "ushort", "short", "float", "bool" };}} private string readWords = "";/// <summary>/// 读数结果/// </summary>public string ReadWords{get { return readWords; }set{readWords = value;OnPropertyChanged();}}private string writeWords = "";/// <summary>/// 写入数据/// </summary>public string WriteWords{get { return writeWords; }set{writeWords = value;OnPropertyChanged();}}private string connectWords = "当前未连接";/// <summary>/// 连接状态/// </summary>public string ConnectWords{get { return connectWords; }set{connectWords = value;OnPropertyChanged();}}/// </summary>/// <summary>/// 登录按钮的命令处理/// </summary>public ICommand LoginCommand{get{return new RelayCommand(o =>{var name = HostName;var port = HostPort;finsTcp = new FinsTcp(name, Convert.ToInt32(port), 10, 04);// 创建连接 var result = finsTcp.Connect();// 开始连接PLCif (!result.IsSuccessed){ShowError(result.Message, "错误");return;}ShowMessage("PLC连接成功", "提示");ConnectWords = "PLC连接成功";});}}/// </summary>/// <summary>/// 读取按钮的命令处理/// </summary>public ICommand ReadCommand{get{return new RelayCommand(o =>{var d = ReadPLCModel; //内存地址string plcAddr = ReadPLCModel.Area + ReadPLCModel.Address;//读取数量ushort readCount = ushort.Parse(ReadPLCModel.Count);//数据类型string dataType = ReadPLCModel.DataType;switch (dataType){case "ushort":var datas = finsTcp.Read<ushort>(plcAddr, readCount);if (!datas.IsSuccessed){ShowMessage(datas.Message, "提示");return;}ReadWords = string.Join(",", datas.Datas);break;case "short":var datas2 = finsTcp.Read<short>(plcAddr, readCount);if (!datas2.IsSuccessed){ShowMessage(datas2.Message, "提示");return;}ReadWords = string.Join(",", datas2.Datas);break;case "float":var datas3 = finsTcp.Read<float>(plcAddr, readCount);if (!datas3.IsSuccessed){ShowMessage(datas3.Message, "提示");return;}ReadWords = string.Join(",", datas3.Datas);break;case "bool":var datas4 = finsTcp.Read<bool>(plcAddr, readCount);if (!datas4.IsSuccessed){ShowMessage(datas4.Message, "提示");return;}ReadWords = string.Join(",", datas4.Datas);break;}});}}/// </summary>/// <summary>/// 写入按钮的命令处理/// </summary>public ICommand WriteCommand{get{return new RelayCommand(o =>{var d = WritePLCModel;//内存地址string plcAddr = WritePLCModel.Area + WritePLCModel.Address;//写入数量 ushort writeCount = ushort.Parse(WritePLCModel.Count);//数据类型string dataType = WritePLCModel.DataType;//实际数量string objWriteVals = WriteWords;ushort objWCount = (ushort)objWriteVals.Split(',').Length;//实际数量与要求数量不一致,不允许操作if (writeCount != objWCount){ShowError("写入值的数量不正确!");return;}List<string> vals = objWriteVals.Split(',').ToList();switch (dataType){case "ushort"://实际数值转换成list集合ushort类型List<ushort> objushort = new List<ushort>();vals.ForEach((x) =>{objushort.Add(ushort.Parse(x));});var finish1 = finsTcp.Write(objushort, plcAddr);if (finish1.IsSuccessed){ShowMessage(finish1.Message, "提示");}break;case "short"://实际数值转换成list集合 short类型List<short> objshort = new List<short>();vals.ForEach((x) =>{objshort.Add(short.Parse(x));});var finish2 = finsTcp.Write(objshort, plcAddr);if (finish2.IsSuccessed){ShowMessage(finish2.Message, "提示");}break;case "float"://实际数值转换成list集合 floatList<float> objfloat = new List<float>();vals.ForEach((x) =>{objfloat.Add(float.Parse(x));});var finish3 = finsTcp.Write(objfloat, plcAddr);if (finish3.IsSuccessed){ShowMessage(finish3.Message, "提示");}break;case "bool"://实际数值转换成list集合boolList<bool> objbool = new List<bool>();vals.ForEach((x) =>{if (x == "1"){objbool.Add(true);}else{objbool.Add(false);}});var finish4 = finsTcp.Write(objbool, plcAddr);if (finish4.IsSuccessed){ShowMessage(finish4.Message, "提示");}break;}});}}}
}

2.7 主界面样式

首先添加资源文件

 

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"><!--定义通用的按钮样式--><Style TargetType="{x:Type Button}" x:Key="btnBaseStyle"><Setter Property="Height" Value="22"/><Setter Property="Width" Value="60"/><Setter Property="FontFamily" Value="微软雅黑"/><Setter Property="Margin" Value="3,0"/><Setter Property="FontSize" Value="16"/><Setter Property="FontWeight" Value="Bold"/><Setter Property="Foreground"  Value="Blue"/></Style><!--TextBox默认样式--><Style TargetType="{x:Type TextBox}" x:Key="txtTextBoxStyle"><Setter Property="Width" Value="150"/><Setter Property="Height" Value="25"/><Setter Property="BorderBrush" Value="#FF105190"/><Setter Property="BorderThickness" Value="1"/><Setter Property="Margin" Value="2,0"/><Setter Property="VerticalContentAlignment" Value="Center"/><Setter Property="Background"><Setter.Value><LinearGradientBrush StartPoint="0.5,0" EndPoint="0.5,1"><GradientStop Color="White" Offset="0"/><GradientStop Color="#FFE4E4E4" Offset="1"/></LinearGradientBrush></Setter.Value></Setter></Style><!--TextBlock默认样式--><Style TargetType="{x:Type TextBlock}" x:Key="txtTextBlockStyle"><Setter Property="Margin" Value="1"/><Setter Property="Height" Value="15"/></Style><!--页面下拉框样式--><LinearGradientBrush x:Key="ComboBox.Static.Background" EndPoint="0,1" StartPoint="0,0"><GradientStop Color="White" Offset="0"/><GradientStop Color="#FFE4E4E4" Offset="1"/></LinearGradientBrush><SolidColorBrush x:Key="ComboBox.Static.Border" Color="#FF105190"/><!--combox默认样式--><Style x:Key="cboStyle" TargetType="{x:Type ComboBox}"><Setter Property="Background" Value="{StaticResource ComboBox.Static.Background}"/><Setter Property="BorderBrush" Value="{StaticResource ComboBox.Static.Border}"/><Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.WindowTextBrushKey}}"/><Setter Property="Width" Value="150"/><Setter Property="Height" Value="25"/><Setter Property="BorderThickness" Value="1"/><Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Auto"/><Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto"/><Setter Property="Padding" Value="6,3,5,3"/><Setter Property="ScrollViewer.CanContentScroll" Value="true"/><Setter Property="ScrollViewer.PanningMode" Value="Both"/><Setter Property="Stylus.IsFlicksEnabled" Value="False"/></Style>
</ResourceDictionary>

 使用资源文件 

2.8 主界面布局

 

<Window x:Class="OmronFinsWPFApp.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:OmronFinsWPFApp.ViewModel"mc:Ignorable="d"   WindowStartupLocation="CenterScreen"FontSize="13" FontFamily="Microsoft YaHei" FontWeight="ExtraLight" Title="欧姆龙PLC通讯工具" Height="430" Width="860" Name="loginWin"><Window.DataContext><local:MainViewModel/></Window.DataContext><Grid Background="Honeydew" ShowGridLines="true"><Grid.RowDefinitions><RowDefinition Height="60"/><RowDefinition/></Grid.RowDefinitions><!--第一行标题--><TextBlock Grid.Row="0" Text="C#利用Fins协议实现欧姆龙PLC的数据读写" FontSize="22" VerticalAlignment="Center" Margin="20,0" FontWeight="Bold" /><!--第二行信息--><Grid Grid.Row="1"><Grid.ColumnDefinitions><ColumnDefinition Width="200"/><ColumnDefinition/></Grid.ColumnDefinitions> <StackPanel Grid.Column="0" Margin="20"><TextBlock Text="PLC地址"/><TextBox   Height="30" VerticalContentAlignment="Center" Padding="5,0" Margin="0,10" Text="{Binding HostName}"  /> <TextBlock Text="端口号" Margin="0,10,0,0"/><TextBox  Height="30" VerticalContentAlignment="Center" Padding="5,0" Margin="0,10" Text="{Binding HostPort}"  /> <Button Content="连接" Margin="0,30,0,0" Height="30"   Command="{Binding LoginCommand}" CommandParameter="{Binding ElementName=loginWin}"  /><Button Content="断开" Margin="0,10" Height="30" /><TextBlock  Text="{Binding ConnectWords,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"  Margin="0,10,0,0"  Foreground="Blue"/></StackPanel><Grid Grid.Column="1"><Grid.RowDefinitions><RowDefinition Height="60"/><RowDefinition Height="80"/><RowDefinition Height="30"/><RowDefinition Height="60"/><RowDefinition Height="80"/></Grid.RowDefinitions><Grid.ColumnDefinitions><ColumnDefinition/><ColumnDefinition/></Grid.ColumnDefinitions><StackPanel Orientation="Horizontal" Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2" Margin="10"><TextBlock     Text="存储区:"  Style="{StaticResource  txtTextBlockStyle}" ></TextBlock><ComboBox  ItemsSource="{Binding CboCustTypes}" SelectedValue="{Binding  ReadPLCModel.Area}"  Width="70"  Style="{StaticResource cboStyle}"></ComboBox><TextBlock   Text="数据类型:"  Style="{StaticResource  txtTextBlockStyle}" ></TextBlock><ComboBox     ItemsSource="{Binding CboCustDatas}" SelectedValue="{Binding ReadPLCModel.DataType}"  Width="70" Style="{StaticResource cboStyle}"></ComboBox><TextBlock   Text="地址:" Style="{StaticResource  txtTextBlockStyle}" ></TextBlock><TextBox    Text="{Binding ReadPLCModel.Address}"  Width="100"  Style="{StaticResource  txtTextBoxStyle}" /><TextBlock   Text="数量:" Style="{StaticResource  txtTextBlockStyle}" ></TextBlock><TextBox    Text="{Binding ReadPLCModel.Count}"  Width="60" Style="{StaticResource  txtTextBoxStyle}"  /><Button Content="读取" Height="30" Width="100"  Command="{Binding ReadCommand}" CommandParameter="{Binding ElementName=loginWin}" Style="{StaticResource btnBaseStyle}"  /></StackPanel><StackPanel Orientation="Vertical" Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2"  Margin="10"><TextBlock Text="读取结果(多个数据之间用逗号隔开)"  Style="{StaticResource  txtTextBlockStyle}" Margin="0 5 0 9"></TextBlock><TextBox   Text="{Binding ReadWords,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"  Width="600" Style="{StaticResource  txtTextBoxStyle}"    /></StackPanel><StackPanel Orientation="Horizontal" Margin="5" Grid.Row="2"  Grid.Column="0" Grid.ColumnSpan="2" Background="#4490AC" Width="600"></StackPanel><StackPanel Orientation="Horizontal" Grid.Row="3" Grid.Column="0" Grid.ColumnSpan="2"  Margin="10"><TextBlock     Text="存储区:" Style="{StaticResource  txtTextBlockStyle}" ></TextBlock><ComboBox    ItemsSource="{Binding CboCustTypes}" SelectedValue="{Binding WritePLCModel.Area }"  Width="70"  Style="{StaticResource cboStyle}"></ComboBox><TextBlock   Text="数据类型:" Style="{StaticResource  txtTextBlockStyle}" ></TextBlock><ComboBox     ItemsSource="{Binding CboCustDatas}" SelectedValue="{Binding WritePLCModel.DataType }"  Width="70"  Style="{StaticResource cboStyle}"></ComboBox><TextBlock   Text="地址:" Style="{StaticResource  txtTextBlockStyle}" ></TextBlock><TextBox   Text="{Binding  WritePLCModel.Address }"  Width="100"  Style="{StaticResource  txtTextBoxStyle}"  /><TextBlock   Text="数量:" Style="{StaticResource  txtTextBlockStyle}" ></TextBlock><TextBox    Text="{Binding WritePLCModel.Count}"  Width="60"   Style="{StaticResource  txtTextBoxStyle}"  /><Button Content="写入" Height="30" Width="100"   Command="{Binding WriteCommand}" CommandParameter="{Binding ElementName=loginWin}" Style="{StaticResource btnBaseStyle}" /></StackPanel><StackPanel Orientation="Vertical" Grid.Row="4" Grid.Column="0" Grid.ColumnSpan="2"  Margin="10"><TextBlock   Text="写入数据(多个数据之间用逗号隔开)" Style="{StaticResource  txtTextBlockStyle}" Margin="0 5 0 9" ></TextBlock><TextBox    Text="{Binding WriteWords ,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"  Width="600" Style="{StaticResource  txtTextBoxStyle}"  /></StackPanel></Grid></Grid></Grid>
</Window>

运行起来效果

3、测试软件

3.1 测试PLC连接

3.2 读取dm区100的short类型

3.3 读取h区100的ushort类型

3.4 读取w区100的float类型

3.5 读取cio区100的bool类型

3.6 写入DM区110的short类型

 

 

3.7 写入H区110的ushort类型

3.8 写入W区110的float类型

3.9 写入CIO区110的bool类型

 

全部通讯报文 

4、小结

本例子用到WPF的MVVM模式,不是winform中的按钮点击事件,是后台绑定viewmodel,用数据驱动页面控件,跟vue中的mvvm渲染数据方式一样,跟微信小程序的MVVM模式一样的,这就实现了界面与数据的分离。

打字不易,截图不易,代码不易,准备不易,原创不易,多多点赞收藏,江湖有你,共同致富。

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

国图公考:2024年上半年中小学教师资格考试(笔试)报考须知

(一)信息填报时间&#xff1a;2024年1月12日9:00至1月15日16&#xff1a;00 (二)信息确认时间&#xff1a;2024年1月13日9:00至1月16日16&#xff1a;00 (三)网上缴费时间&#xff1a;2024年1月13日9:00至1月17日24&#xff1a;00

新年福利|这款价值数万的报表工具永久免费了

随着数据资产的价值逐渐凸显&#xff0c;越来越多的企业会希望采用报表工具来处理数据分析&#xff0c;了解业务经营状况&#xff0c;从而辅助经营决策。不过&#xff0c;企业在选型报表工具的时候经常会遇到以下几个问题&#xff1a; 各个报表工具有很多功能和特性&#xff0c…

硬盘基本知识(磁头、磁道、扇区、柱面)

概述 盘片&#xff08;platter&#xff09; 磁头&#xff08;head&#xff09; 磁道&#xff08;track&#xff09; 扇区&#xff08;sector&#xff09; 柱面&#xff08;cylinder&#xff09; 盘片 片面 和 磁头 硬盘中一般会有多个盘片组成&#xff0c;每个盘片包含两个面…

大数据毕设分享 flink大数据淘宝用户行为数据实时分析与可视化

文章目录 0 前言1、环境准备1.1 flink 下载相关 jar 包1.2 生成 kafka 数据1.3 开发前的三个小 tip 2、flink-sql 客户端编写运行 sql2.1 创建 kafka 数据源表2.2 指标统计&#xff1a;每小时成交量2.2.1 创建 es 结果表&#xff0c; 存放每小时的成交量2.2.2 执行 sql &#x…

商品小程序(6.商品详情)

目录 一、获取商品详情数据二、渲染商品详情页的UI结构1、渲染轮播图区域2、实现轮播图预览效果3、渲染商品信息区域4、渲染商品详情信息5、解决商品价格闪烁的问题 三、渲染详情页底部的商品导航区域1、渲染商品导航区域的UI结构2、点击跳转到购物车页面 本章主要完成商品详情…

大数据框架ElasticSearch学习网站,让你的技能瞬间升级!

介绍&#xff1a;Elasticsearch是一个分布式、免费和开放的搜索和分析引擎&#xff0c;它适用于所有类型的数据&#xff0c;包括文本Elasticsearch是一个分布式、免费和开放的搜索和分析引擎&#xff0c;它适用于所有类型的数据&#xff0c;包括文本、数字、地理空间、结构化和…

DVenom:一款功能强大的Shellcode加密封装和加载工具

关于DVenom DVenom是一款功能强大的Shellcode加密封装和加载工具&#xff0c;该工具专为红队研究人员设计&#xff0c;可以帮助红队成员通过对Shellcode执行加密封装和加载实现反病毒产品的安全检测绕过。 功能介绍 1、支持绕过某些热门反病毒产品&#xff1b; 2、提供了多种…

解决uniapp打包成apk后uni.getStorageSync获取不到值

uniapp写的项目&#xff0c;在hbuilderx中云打包成apk后我在登录存储的token死都获取不到&#xff0c;导致后续接口请求头没有token连接不到接口&#xff0c;只有运行到手机或者模拟器还有打包成apk后是获取不到&#xff0c;其他的小程序还有网页都可以获取到 试过了很多种方法…

美洽获评2023年度“最佳数字化服务商”,产品优势赋能企业智能转型

日前&#xff0c;由知名学习交流平台人人都是产品经理举办的“2023年度评选”活动圆满落幕&#xff0c;美洽凭借在企业服务领域的技术实力与优秀实践成果脱颖而出&#xff0c;入围年度产品评选榜单&#xff0c;获评2023年度“最佳数字化服务商”。 人人都是产品经理成立于2010年…

什么是负载均衡?什么情况下又会用到负载均衡

什么是负载均衡 在大型的网络应用中&#xff0c;使用多台服务器提供同一个服务是常有的事。平均分配每台服务器上的压力、将压力分散的方法就叫做负载均衡。 [利用 DNS来实现服务器流量的负载均衡&#xff0c;原理是“给网站访问者随机分配不同ip”] 什么情况下会用到负载均…

js逆向第9例:猿人学第2题-js混淆-动态cookie1

题目2:提取全部5页发布日热度的值,计算所有值的加和,并提交答案 (感谢蔡老板为本题提供混淆方案) 既然题目已经给出了cookie问题,那就从cookie入手,控制台找到数据请求地址 可以看到如下加密字符串m类似md5,后面跟着时间戳 m=45cc41dcdb15159ebb50564635f8e362|1704301…

使用PowerJob做任务调度模块

最近项目中使用了PowerJob做任务调度模块&#xff0c;感觉这个框架真香&#xff0c;今天我们就来深入了解一下新一代的定时任务框架——PowerJob&#xff01; 简介 PowerJob是基于java开发的企业级的分布式任务调度平台&#xff0c;与xxl-job一样&#xff0c;基于web页面实现…