主页 > 游戏开发  > 

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


1、介绍

上节开发了一个winform版的通讯测试工具,这节再搞个wpf版的,wpf是什么?请自行百度,也可以看前面的博客,WPF真入门教程,具体看这个,WPF真入门教程26--项目案例--欧姆龙PLC通讯工具,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; } #endregion private 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); else return 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();// 开始连接PLC if (!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集合 float List<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集合bool List<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模式一样的,这就实现了界面与数据的分离。

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

标签:

C#上位机与欧姆龙PLC的通信10----开发专用的通讯工具软件(WPF版)由讯客互联游戏开发栏目发布,感谢您对讯客互联的认可,以及对我们原创作品以及文章的青睐,非常欢迎各位朋友分享到个人网站或者朋友圈,但转载请说明文章出处“C#上位机与欧姆龙PLC的通信10----开发专用的通讯工具软件(WPF版)