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

1、介绍

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

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

前面的winform界面:

C#上位机与欧姆龙PLC的通信10----开发专用的通讯工具软件(WPF版)_第2张图片 2、开工干

2.1 创建wpf项目

C#上位机与欧姆龙PLC的通信10----开发专用的通讯工具软件(WPF版)_第3张图片C#上位机与欧姆龙PLC的通信10----开发专用的通讯工具软件(WPF版)_第4张图片C#上位机与欧姆龙PLC的通信10----开发专用的通讯工具软件(WPF版)_第5张图片

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

 C#上位机与欧姆龙PLC的通信10----开发专用的通讯工具软件(WPF版)_第6张图片2.3 创建自定义的消息弹窗

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

MsgBoxWindow.xaml代码


    
        
    
    
        
            
                
            
            
                
                    
                    
                
            
            
                
                    
                    
                    
                
                
                    
                        
                            
                            
                        
                    
                
                
                
                    
                    
                
                
                
                    

 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
{
    /// 
    /// MsgBoxWindow.xaml 的交互逻辑
    /// 
    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;
        }

        /// 
        /// 显示按钮类型
        /// 
        public enum CustomMessageBoxButton
        {
            OK = 1,
            OKCancel = 2,
            YesNo = 3,
            YesNoCancel = 4
        }

        /// 
        /// 消息框返回值
        /// 
        public enum CustomMessageBoxResult
        {
            None = 0,//用户直接关闭消息框
            OK = 1,//用户点击了确定按钮
            Cancel = 2,//用户点击了取消按钮
            Yes = 3,//用户点击了是按钮
            No = 4//用户点击了否按钮
        }

        /// 
        /// 图标类型
        /// 
        public enum CustomMessageBoxIcon
        {
            None = 0,
            Error = 1,
            Question = 2,
            Infomation = 3
        }

        #region 页面属性定义
        /// 
        /// 消息文本
        /// 
        public string MessageBoxText { get; set; }
        /// 
        /// 消息框标题
        /// 
        public string MessageTitle { get; set; }
        /// 
        /// 图标路径
        /// 
        public string ImagePath { get; set; }
        /// 
        /// 显示确定
        /// 
        public Visibility OkButtonVisibility { get; set; }
        /// 
        /// 显示取消
        /// 
        public Visibility CancelButtonVisibility { get; set; }
        /// 
        /// 显示是
        /// 
        public Visibility YesButtonVisibility { get; set; }
        /// 
        /// 显示否
        /// 
        public Visibility NoButtonVisibility { get; set; }
        /// 
        /// 消息框返回值
        /// 
        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();
        }

        /// 
        /// 消息框拖动
        /// 
        /// 
        /// 
        private void Grid_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            this.DragMove();
        }
        /// 
        /// 显示消息框
        /// 
        /// 
        /// 
        /// 
        /// 
        /// 
        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文件,并引用到项目中

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

2.5 添加目录及命令类RelayCommand

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

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;

namespace OmronFinsWPFApp.Common
{
    /// 
    /// 命令实现类
    /// 
    public class RelayCommand : ICommand
    {
        public event EventHandler CanExecuteChanged;
        /// 
        /// 要执行的操作
        /// 
        private Action executeActions;
        /// 
        /// 是否可以执行的委托
        /// 
        private Func canExecuteFunc;
        /// 
        /// 构造函数 无参构造
        /// 
        public RelayCommand() { }
        /// 
        /// 通过执行的委托构造
        /// 
        /// 
        public RelayCommand(Action execute) : this(execute, null)
        {

        }
        /// 
        /// 通过执行的操作与是否可执行的委托
        /// 
        /// 要执行的操作
        /// 是否可以被执行
        public RelayCommand(Action execute, Func canExecute)
        {
            this.executeActions = execute;
            this.canExecuteFunc = canExecute;
        }

        /// 
        /// 命令是否可以执行
        /// 
        /// 
        /// 
        public bool CanExecute(object parameter)
        {
            if (canExecuteFunc != null)
                return this.canExecuteFunc(parameter);
            else
                return true;
        }

        /// 
        /// 要执行的操作
        /// 
        /// 
        public void Execute(object parameter)
        {
            if (executeActions == null)
                return;
            this.executeActions(parameter);
        }

        /// 
        /// 执行CanExecuteChanged事件
        /// 
        public void OnCanExecuteChanged()
        {
            this.CanExecuteChanged?.Invoke(this, new EventArgs());
        }
    }
}

2.6 添加视图模型类对象

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

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
{
    /// 
    /// 视图模型基类
    /// 
    public class ViewModelBase : INotifyPropertyChanged
    {
        /// 
        /// 属性值发生更改时触发
        /// 
        public event PropertyChangedEventHandler PropertyChanged;



        /// 
        /// 执行更改
        /// C#5.0中的新特性CallerMemberName
        /// 
        /// 
        protected void OnPropertyChanged([CallerMemberName] string propertyName = "")
        {
            if (PropertyChanged != null)
            {
                PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyName));
            }
        }


        /// 
        /// 成功消息提示
        /// 
        /// 
        /// 
        /// 
        public void ShowMessage(string message, string title = "提示", CustomMessageBoxButton buttons = CustomMessageBoxButton.OK)
        {
            Show(message, title, buttons, CustomMessageBoxIcon.Infomation);
        }

        /// 
        /// 错误消息框
        /// 
        /// 
        /// 
        /// 
        public void ShowError(string message, string title = "错误", CustomMessageBoxButton buttons = CustomMessageBoxButton.OK)
        {
            Show(message, title, buttons, CustomMessageBoxIcon.Error);
        }

        /// 
        /// 询问消息框
        /// 
        /// 
        /// 
        /// 
        /// 
        public CustomMessageBoxResult ShowQuestion(string message, string title = "询问", CustomMessageBoxButton buttons = CustomMessageBoxButton.OKCancel)
        {
            return Show(message, title, buttons, CustomMessageBoxIcon.Question);
        }



    }
}

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

 

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
{
    /// 
    /// 视图模型
    /// 
    public class MainViewModel : ViewModelBase
    {
        /// 
        /// finstcp对象
        /// 
        FinsTcp finsTcp; 
        

        PLCMemoryModel readPLCModel = SetInitModel();
        /// 
        /// 读取PLC
        /// 
        public PLCMemoryModel ReadPLCModel
        {
            get { return readPLCModel; }
            set
            {
                readPLCModel = ReadPLCModel;
                OnPropertyChanged();//属性通知
            }
        }

        PLCMemoryModel writePLCModel = SetInitModel();
        /// 
        /// 写入PLC
        /// 
        public PLCMemoryModel WritePLCModel
        {
            get { return writePLCModel; }
            set
            {
                writePLCModel = WritePLCModel;
                OnPropertyChanged();
            }
        }
        /// 
        /// 初始化页面参数
        /// 
        /// 
        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";
        /// 
        /// PLC地址
        /// 
        public string HostName
        {
            get
            {
                return hostName;
            }
            set
            {
                hostName = value;
            }
        }

        private string hostPort = "7788";
        /// 
        /// PLC端口
        /// 
        public string HostPort
        {
            get { return hostPort; }
            set
            {
                hostPort = value;
            }
        }


        /// 
        /// 存储区下拉框数据源
        /// 
        public List CboCustTypes
        {
            get
            {
                return new List() { "DM", "H", "W", "CIO" };
            }
        }

        /// 
        /// 数据类型
        /// 
        public List CboCustDatas
        {
            get
            {
                return new List() { "ushort", "short", "float", "bool" };
            }
        } 

        private string readWords = "";
        /// 
        /// 读数结果
        /// 
        public string ReadWords
        {
            get { return readWords; }
            set
            {
                readWords = value;
                OnPropertyChanged();
            }
        }
        private string writeWords = "";
        /// 
        /// 写入数据
        /// 
        public string WriteWords
        {
            get { return writeWords; }
            set
            {
                writeWords = value;
                OnPropertyChanged();
            }
        }

        private string connectWords = "当前未连接";
        /// 
        /// 连接状态
        /// 
        public string ConnectWords
        {
            get { return connectWords; }
            set
            {
                connectWords = value;
                OnPropertyChanged();
            }
        }
         

        /// 
        /// 
        /// 登录按钮的命令处理
        /// 
        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连接成功";
                });
            }
        }

        /// 
        /// 
        /// 读取按钮的命令处理
        /// 
        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(plcAddr, readCount);
                            if (!datas.IsSuccessed)
                            {
                                ShowMessage(datas.Message, "提示");
                                return;
                            }
                            ReadWords = string.Join(",", datas.Datas);
                            break;
                        case "short":
                            var datas2 = finsTcp.Read(plcAddr, readCount);
                            if (!datas2.IsSuccessed)
                            {
                                ShowMessage(datas2.Message, "提示");
                                return;
                            }
                            ReadWords = string.Join(",", datas2.Datas);
                            break;
                        case "float":
                            var datas3 = finsTcp.Read(plcAddr, readCount);
                            if (!datas3.IsSuccessed)
                            {
                                ShowMessage(datas3.Message, "提示");
                                return;
                            }
                            ReadWords = string.Join(",", datas3.Datas);
                            break;
                        case "bool":
                            var datas4 = finsTcp.Read(plcAddr, readCount);
                            if (!datas4.IsSuccessed)
                            {
                                ShowMessage(datas4.Message, "提示");
                                return;
                            }
                            ReadWords = string.Join(",", datas4.Datas);
                            break;
                    }
                });
            }
        }


        /// 
        /// 
        /// 写入按钮的命令处理
        /// 
        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 vals = objWriteVals.Split(',').ToList();
                    switch (dataType)
                    {
                        case "ushort":
                            //实际数值转换成list集合ushort类型
                            List objushort = new List();
                            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 objshort = new List();
                            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 objfloat = new List();
                            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 objbool = new List();
                            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 主界面样式

首先添加资源文件

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

 

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


    
    

    
    

    
    

    
    
        
        
    
    

    
    

 使用资源文件 

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

2.8 主界面布局

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

 


    
        
    
    
        
            
            
        
        
        
        
        
            
                
                
             

            
                
                 
                
                 
                

运行起来效果

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

3、测试软件

3.1 测试PLC连接

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

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

3.2 读取dm区100的short类型

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

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

3.3 读取h区100的ushort类型

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

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

3.4 读取w区100的float类型

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

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

3.5 读取cio区100的bool类型

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

3.6 写入DM区110的short类型

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

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

3.7 写入H区110的ushort类型

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

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

3.8 写入W区110的float类型

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

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

3.9 写入CIO区110的bool类型

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

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

全部通讯报文 

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

4、小结

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

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

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

你可能感兴趣的:(c#,wpf,开发语言,通讯库,PLC,欧姆龙)