本文主要是介绍C#上位机与三菱PLC的通信11---开发自己的通讯工具软件(WPF版),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
1、先看颜值
2、开始干
1、创建项目
2、引入前面的通讯库
创建目录将前面生成的通讯库dll文件复制到项目的目录
本项目引入dll文件
3、创建命令基类
RelayCommand.cs代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;namespace MitsubishiMcToolWPF.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());}}
}
4、创建PLC实体类
PLCMemoryModel.cs代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace MitsubishiMcToolWPF.Model
{/// <summary>/// PLC内存模型类/// </summary>public class PLCMemoryModel{/// <summary>/// 存储区/// </summary>public string Area { get; set; } = "";/// <summary>/// 地址/// </summary>public string Address { get; set; } = "";/// <summary>/// 数据类型/// </summary>public string DataType { get; set; } = "";/// <summary>/// 读取或写入数据/// </summary>public string Count { get; set; } = "";}
}
5、添加资源字典,即样式文件
CommonResource.xaml完整代码
<!--读取写入Button按钮样式--> <Style x:Key="ButtonStyle" TargetType="Button"><Setter Property="Background" Value="#3F85FF"></Setter><Setter Property="Foreground" Value="White"></Setter><Setter Property="FocusVisualStyle" Value="{x:Null}"></Setter><Setter Property="Margin" Value="5"></Setter><Setter Property="Height" Value="90"></Setter><Setter Property="FontSize" Value="16"></Setter><!--模板的样式--><Setter Property="Template"><Setter.Value><!--Button单选按钮样式--><ControlTemplate TargetType="Button"><Grid ><Border Background="{TemplateBinding Background}" CornerRadius="5" ><TextBlock Margin="10 5 10 5" Text="{TemplateBinding Content}" FontSize="{TemplateBinding FontSize}" HorizontalAlignment="Center" VerticalAlignment="Center"></TextBlock></Border></Grid><ControlTemplate.Triggers><!--鼠标放上去时的触发器--><Trigger Property="IsMouseOver" Value="True"><Setter Property="Background" Value="#1E5FD1" ></Setter></Trigger></ControlTemplate.Triggers></ControlTemplate></Setter.Value></Setter></Style><!--连接断开按钮样式--><Style x:Key="ConnStyle" TargetType="Button"><Setter Property="Background" Value="#3F8666"></Setter><Setter Property="Foreground" Value="White"></Setter><Setter Property="FocusVisualStyle" Value="{x:Null}"></Setter><Setter Property="Margin" Value="5"></Setter><Setter Property="Height" Value="60"></Setter><Setter Property="FontSize" Value="16"></Setter><!--模板的样式--><Setter Property="Template"><Setter.Value><!--Button单选按钮样式--><ControlTemplate TargetType="Button"><Grid ><Border Background="{TemplateBinding Background}" CornerRadius="5" ><TextBlock Margin="10 5 10 5" Text="{TemplateBinding Content}" FontSize="{TemplateBinding FontSize}" HorizontalAlignment="Center" VerticalAlignment="Center"></TextBlock></Border></Grid><ControlTemplate.Triggers><!--鼠标放上去时的触发器--><Trigger Property="IsMouseOver" Value="True"><Setter Property="Background" Value="#1E5FD1" ></Setter></Trigger></ControlTemplate.Triggers></ControlTemplate></Setter.Value></Setter></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>
6、创建viewmodel
viewmodel是视图模型,wpf采用的是mvvm的渲染模式,即控件绑定对象的属性,属性发生更改时,驱动控件的数据显示,而控件动作是由命令command执行
1、模型基类
ViewModelBase.cs代码
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 MitsubishiMcToolWPF.MsgBoxWindow;namespace MitsubishiMcToolWPF.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);}}
}
2、主页模型mainviewmodel
MainViewModel.cs代码
using Mitsubishi.Communication.MC.Mitsubishi;
using MitsubishiMcToolWPF.Common;
using MitsubishiMcToolWPF.Model;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;namespace MitsubishiMcToolWPF.ViewModel
{/// <summary>/// 视图模型/// </summary>public class MainViewModel : ViewModelBase{/// <summary>/// mctcp对象/// </summary>A3E mctcp;#region 属性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 = "D";model.DataType = "short";model.Address = "100";model.Count = "1";return model;}private string hostName = "192.168.1.7";/// <summary>/// PLC地址/// </summary>public string HostName{get{return hostName;}set{hostName = value;}}private string hostPort = "6000";/// <summary>/// PLC端口/// </summary>public string HostPort{get { return hostPort; }set{hostPort = value;}}/// <summary>/// 存储区下拉框数据源/// </summary>public List<string> CboCustTypes{get{return new List<string>() { "D", "X", "Y", "M", "R", "S", "TS" };}}/// <summary>/// 数据类型/// </summary>public List<string> CboCustDatas{get{return new List<string>() { "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();}}#endregion#region 命令/// </summary>/// <summary>///连接按钮的命令 /// </summary>public ICommand ConnCommand{get{return new RelayCommand(o =>{var name = HostName;var port = HostPort;mctcp = new A3E(name, short.Parse(port));// 创建连接 var result = mctcp.Connect();// 开始连接PLCif (!result.IsSuccessed){ShowError(result.Message, "错误");return;}ConnectWords = "PLC已连接";ShowMessage("PLC连接成功", "提示");});}}/// </summary>/// <summary>///断开按钮的命令 /// </summary>public ICommand CloseCommand{get{return new RelayCommand(o =>{if (mctcp == null){ShowError("PLC没有连接,不能断开", "错误");return;}mctcp = null;ConnectWords = "PLC已断开";});}}/// </summary>/// <summary>/// 读取按钮的命令 /// </summary>public ICommand ReadCommand{get{return new RelayCommand(o =>{ReadWords = "";var d = ReadPLCModel;if (mctcp == null){ShowError("PLC未连接,不能读取数据", "错误");return;}//内存地址string plcAddr = ReadPLCModel.Area + ReadPLCModel.Address;//读取数量short readCount = short.Parse(ReadPLCModel.Count);//数据类型string dataType = ReadPLCModel.DataType;switch (dataType){case "short":var datas2 = mctcp.Read<short>(plcAddr, readCount);if (!datas2.IsSuccessed){ShowMessage(datas2.Message, "提示");return;}ReadWords = string.Join(",", datas2.Datas);break;case "float":var datas3 = mctcp.Read<float>(plcAddr, readCount);if (!datas3.IsSuccessed){ShowMessage(datas3.Message, "提示");return;}ReadWords = string.Join(",", datas3.Datas);break;case "bool":var datas4 = mctcp.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 =>{if (mctcp == null){ShowError("PLC未连接,不能写入数据", "错误");return;}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 "short"://实际数值转换成list集合 short类型List<short> objshort = new List<short>();vals.ForEach((x) =>{objshort.Add(short.Parse(x));});var finish2 = mctcp.Write<short>(objshort, plcAddr);if (finish2.IsSuccessed){ShowMessage("写入成功", "提示");}break;case "float"://实际数值转换成list集合 floatList<float> objfloat = new List<float>();vals.ForEach((x) =>{objfloat.Add(float.Parse(x));});var finish3 = mctcp.Write<float>(objfloat, plcAddr);if (finish3.IsSuccessed){ShowMessage("写入成功", "提示");}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 = mctcp.Write<bool>(objbool, plcAddr);if (finish4.IsSuccessed){ShowMessage("写入成功", "提示");}break;}});}}#endregion}
}
7、主界面布局
MainWindow.xaml完整代码
<Window x:Class="MitsubishiMcToolWPF.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:MitsubishiMcToolWPF.ViewModel"mc:Ignorable="d" FontSize="13" FontFamily="Microsoft YaHei" ResizeMode="CanMinimize" Title="三菱PLC通讯工具" FontWeight="ExtraLight" WindowStartupLocation="CenterScreen" Height="450" Width="880" Name="mainWin" ><Window.DataContext><local:MainViewModel/></Window.DataContext><Grid ShowGridLines="true"><Grid.RowDefinitions><RowDefinition Height="62"/><RowDefinition/></Grid.RowDefinitions><!--第一行标题--><Grid Grid.Row="0" Background="BlanchedAlmond"><Grid.ColumnDefinitions><ColumnDefinition Width="100" /><ColumnDefinition /></Grid.ColumnDefinitions><Image Grid.Column="0" Source="/imgs/log1.png" Width="60" Height="60" Margin="20,0" /><TextBlock Grid.Column="1" Text="三菱MC协议通讯调试助手(Qna-3E模式)" FontSize="23" VerticalAlignment="Center" FontWeight="Bold" /></Grid><!--第二行信息--><Grid Grid.Row="1" Margin="0 10 0 0"><Grid.ColumnDefinitions><ColumnDefinition Width="200"/><ColumnDefinition Width="4"/><ColumnDefinition/></Grid.ColumnDefinitions><!--第一列PLC参数--><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 ConnCommand}" Style="{StaticResource ConnStyle}" /><Button Content="断开" Margin="0,10" Height="30" Command="{Binding CloseCommand}" Style="{StaticResource ConnStyle}"/><TextBlock Text="{Binding ConnectWords,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" Margin="0,10,0,0" Foreground="Blue"/></StackPanel><!--第二列分隔线--><GridSplitter Grid.Column="1" Background="#4490AC" Width="2" Height="450" Margin="0 -11 0 0"></GridSplitter><!--第三列操作区--><Grid Grid.Column="2"><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}" Margin="0 0 0 0" ></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 ButtonStyle}" /></StackPanel><StackPanel Orientation="Vertical" Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2" Margin="10"><TextBlock Text="读取结果(多个数据之间用逗号隔开)" Style="{StaticResource txtTextBlockStyle}" Margin="0 3 0 9"></TextBlock><TextBox Text="{Binding ReadWords,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" Width="616" Style="{StaticResource txtTextBoxStyle}" Margin="-23,0,0,0" /></StackPanel><StackPanel Orientation="Horizontal" Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="2" Background="#4490AC" Width="706" Height="2" Margin="-1,0,0,0"></StackPanel><StackPanel Orientation="Horizontal" Grid.Row="3" Grid.Column="0" Grid.ColumnSpan="2" Margin="10"><TextBlock Text="存储区:" Style="{StaticResource txtTextBlockStyle}" Margin="0 0 0 0"></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 ButtonStyle}" /></StackPanel><StackPanel Orientation="Vertical" Grid.Row="4" Grid.Column="0" Grid.ColumnSpan="2" Margin="10"><TextBlock Text="写入数据(多个数据之间用逗号隔开)" Style="{StaticResource txtTextBlockStyle}" Margin="0 3 0 9" ></TextBlock><TextBox Text="{Binding WriteWords ,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" Width="616" Style="{StaticResource txtTextBoxStyle}" Margin="-23,0,0,0" /></StackPanel></Grid></Grid></Grid>
</Window>
8、启动MC服务器
9、异常错误处理
10、操作测试
1、连接PLC
2、读取数据,short,float,bool
3、写入数据,short,float
写入short
写入float
3、小结
走过路过不要错过,点赞关注收藏又圈粉,共同致富。
欢迎抄袭,复制,分享,转载,学习,截图..............
欢迎抄袭,复制,分享,转载,学习,截图..............
这篇关于C#上位机与三菱PLC的通信11---开发自己的通讯工具软件(WPF版)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!