WPF OPCUA读写和订阅

WPF OPC读写和订阅

WPF OPC数据读写

安装 OpcUaHelper

在这里插入图片描述

MainWindow.xaml

<Window x:Class="HSAPP.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:HSAPP"
        FontSize="30"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <StackPanel>
            <TextBlock x:Name="showValueText" Text="123"></TextBlock>
            <Button Content="连接OPC" Margin="20" Click="ConnectOPCUA"></Button>
            <Button Content="读写OPC数据" Click="ReadData"></Button>
            <Button Content="读写OPC数据" Click="ReadData"></Button>
        </StackPanel>
    </Grid>
</Window>

MainWindow.xaml.cs

opc.tcp://localhost:5018 为OPC服务器的地址

使用 opcUaClient.ConnectServer(“opc.tcp://localhost:5018”); 连接服务器

可以使用OPC连接工具(Softing OPC Client)查看读取数据的Tag

Softing OPC Client官方下载地址

使用 opcUaClient.ReadNode(“ns=7;s=TEST_VALUE”); 读取数据


using Opc.Ua;
using Opc.Ua.Client;
using OpcUaHelper;

namespace TESTAPP
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {

        // OPC连接对象
        OpcUaClient opcUaClient = null;
        MySqlConnection conn;
        float testValue = 0;

        public MainWindow()
        {
            InitializeComponent();
            opcUaClient = new OpcUaClient();
        }

        private async void ConnectOPCUA(object sender, RoutedEventArgs e)
        {

            try
            {
                // 连接OPC
                opcUaClient.UserIdentity = new UserIdentity(new AnonymousIdentityToken());
                await opcUaClient.ConnectServer("opc.tcp://localhost:5018");
            }
            catch (Exception ex)
            {
                MessageBox.Show("连接失败");
            }
        }

        public void ReadData(object sender, RoutedEventArgs e)
        {
            // 读取数据
            Double value = opcUaClient.ReadNode<Double>("ns=7;s=TEST_VALUE");
            showValueText.Text = value.ToString();
            MessageBox.Show("读取数据:" + value.ToString(),"提示");
            // 写入数据
            opcUaClient.WriteNode<Double>("ns=7;s=TEST_VALUE",12.34);

            // 读取字符串
            string testString = opcUaClient.ReadNode<string>("ns=9;s=TEST_STRING");
            showValueText.Text = testString.ToString();
            MessageBox.Show("读取数据:" + testString.ToString(), "提示");
            // 写入字符串
            opcUaClient.WriteNode<string>("ns=9;s=TEST_STRING", "back hello word");
        }
    }
}

运行效果

第一次点击读写按钮后,读取的是OPC服务器原始值

读取OPC模拟量

在这里插入图片描述

读取OPC字符串

在这里插入图片描述

第二次点击读写按钮后,读取的是设置的OPC服务器值

读取之前写入模拟量

在这里插入图片描述

读取之前写入字符串

在这里插入图片描述

WPF OPC数据订阅

单点订阅

MainWindow.xaml.cs


    public void SubData(object sender, RoutedEventArgs e)
    {

        //单节点数据订阅
        opcUaClient.AddSubscription("TEST_VALUE", "ns=7;s=TEST_VALUE", SubCallback);
        //取消单节点数据订阅
        //m_OpcUaClient.RemoveSubscription("TEST_VALUE");
    }

    //1-单节点数据订阅的回调函数
    private void SubCallback(string key, MonitoredItem monitoredItem, MonitoredItemNotificationEventArgs args)
    {
        // 判断Key是否存在和确定调用线程是否为关联的线程。
        if (!showValueText.Dispatcher.CheckAccess() && key == "TEST_VALUE")
        {
            // 提取key对应的数据
            MonitoredItemNotification notification = args.NotificationValue as MonitoredItemNotification;
            string value = notification.Value.WrappedValue.Value.ToString();

            // 在关联的线程上同步执行
            showValueText.Dispatcher.Invoke(new Action(() => {
                    showValueText.Text = value;
            }));
        }
    }

运行效果

连接OPC服务器,订阅OPC数据后,当其他OPC客户端写这个数据后,showValueText控件数据会实时改变

在这里插入图片描述

多点订阅


    private string[] OPCNodeTags = null;
    
    private void button5_Click( object sender, EventArgs e )
    {
        // 多个节点的订阅
        OPCNodeTags = new string[]
        {
        "ns=7;s=TEST_VALUE1",
        "ns=7;s=TEST_VALUE2",
        "ns=7;s=TEST_VALUE3",
        };
        m_OpcUaClient.AddSubscription( "TEST_VALUE_LIST", OPCNodeTags, SubListCallback );
    }

    private void SubCallback(string key, MonitoredItem monitoredItem, MonitoredItemNotificationEventArgs args)
    {
        if(key == "TEST_VALUE_LIST")
        {
            // 需要区分出来每个不同的节点信息
            MonitoredItemNotification notification = args.NotificationValue as MonitoredItemNotification;
            if (monitoredItem.StartNodeId.ToString( ) == OPCNodeTags[0])
            {
                MessageBox.show(notification.Value.WrappedValue.Value.ToString( ),"提示1");
            }
        }
    }

### 实现WPF应用程序通过OPCUA协议与汇川PLC通信 为了使WPF应用程序能够通过OPCUA协议与汇川PLC进行通信,可以采用`Opc.UaFx.Client`库来简化这一过程。此库提供了丰富的API接口支持多种OPCUA操作,如读取、写入节点数据以及订阅服务。 #### 创建项目并安装依赖项 首先,在Visual Studio中新建一个WPF应用程序项目,并利用NuGet包管理器添加`Opc.UaFx.Client`到当前解决方案里[^2]。 #### 初始化OPCUA客户端配置 在App.xaml.cs文件内完成必要的初始化工作,比如设置端口监听地址服务发现URL等参数: ```csharp using System; using Opc.UaFx; namespace HmiApplication { public partial class App : Application { private static readonly string _endpointUrl = "opc.tcp://localhost:4840"; protected override void OnStartup(StartupEventArgs e){ base.OnStartup(e); var clientSettings = new OpcClientSettings(_endpointUrl, "username", "password"); using (var opcClient = new OpcClient(clientSettings)){ // 进一步处理... } } } } ``` #### 建立连接并与指定节点交互 定义专门的方法来进行具体的业务逻辑编码,例如建立会话链接、获取目标节点ID后执行相应的读/写动作: ```csharp public async Task ReadNodeValueAsync(OpcNodeId nodeId) { try{ await Client.ConnectAsync(); var nodeValue = await Client.ReadNodeValueAsync(nodeId); Console.WriteLine($"Node {nodeId} has value: {nodeValue.Value}"); } catch(Exception ex){ MessageBox.Show(ex.Message,"Error", MessageBoxButton.OKCancel,MessageBoxImage.Error); } finally{ if(Client.IsConnected()){ await Client.DisconnectAsync(); } } } // 调用示例 await ReadNodeValueAsync(new OpcNodeId("ns=2;s=Channel1.Device1.Tag1")); ``` 对于写入操作,则只需替换上述代码片段中的`ReadNodeValueAsync()`函数为对应的`WriteNodeValueAsync()`即可实现向特定路径下的变量赋新值的功能;而对于更复杂的场景需求,还可以考虑引入事件机制或者定时轮询等方式增强程序灵活性响应速度。 #### 使用图表组件展示实时监控信息 除了基本的数据交换外,良好的用户体验同样重要。借助于第三方开源绘图工具集——LiveCharts,可以在界面上直观地反映出工业现场采集来的各类信号变化趋势,从而帮助技术人员快速定位异常状况并作出及时调整措施[^3]。 ```xml <Window x:Class="HmiApplication.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> <!-- 添加 LiveCharts 控件 --> <Grid> <lvc:CartesianChart Series="{Binding SeriesCollection}" /> </Grid> </Window> ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值