使用OpcUaHelper在C# WinForms中连接OPC UA服务器并读取数据
下面是一个完整的示例,展示如何使用OpcUaHelper库在C# WinForms应用程序中连接OPC UA服务器并读取数据。
1. 准备工作
首先,确保你已经安装了OpcUaHelper NuGet包。可以通过NuGet包管理器控制台安装:
Install-Package OpcUaHelper
2. 创建WinForms应用程序
2.1 设计界面
创建一个简单的WinForms窗体,包含以下控件:
- 文本框:用于输入服务器URL
- 连接/断开按钮
- 节点ID文本框
- 读取按钮
- 数据显示区域(如DataGridView或ListBox)
2.2 完整代码示例
using OpcUaHelper;
using System;
using System.Collections.Generic;
using System.Windows.Forms;namespace OpcUaWinFormsClient
{public partial class MainForm : Form{private OpcUaClient opcUaClient = new OpcUaClient();private bool isConnected = false;public MainForm(){InitializeComponent();UpdateUiState();}private void btnConnect_Click(object sender, EventArgs e){if (!isConnected){ConnectToServer();}else{DisconnectFromServer();}}private async void ConnectToServer(){string serverUrl = txtServerUrl.Text.Trim();if (string.IsNullOrEmpty(serverUrl)){MessageBox.Show("请输入有效的服务器URL");return;}try{btnConnect.Enabled = false;lblStatus.Text = "正在连接...";// 连接到服务器await opcUaClient.ConnectServerAsync(serverUrl);isConnected = true;lblStatus.Text = "已连接";MessageBox.Show("连接成功!");}catch (Exception ex){lblStatus.Text = "连接失败";MessageBox.Show($"连接失败: {ex.Message}");}finally{btnConnect.Enabled = true;UpdateUiState();}}private void DisconnectFromServer(){try{opcUaClient.Disconnect();isConnected = false;lblStatus.Text = "已断开";}catch (Exception ex){MessageBox.Show($"断开连接时出错: {ex.Message}");}finally{UpdateUiState();}}private void UpdateUiState(){btnConnect.Text = isConnected ? "断开连接" : "连接";btnRead.Enabled = isConnected;txtNodeId.Enabled = isConnected;}private async void btnRead_Click(object sender, EventArgs e){string nodeId = txtNodeId.Text.Trim();if (string.IsNullOrEmpty(nodeId)){MessageBox.Show("请输入节点ID");return;}try{btnRead.Enabled = false;// 读取单个节点值var value = await opcUaClient.ReadNodeAsync(nodeId);// 显示读取结果lstResults.Items.Add($"节点: {nodeId}, 值: {value}, 类型: {value?.GetType()}");lstResults.TopIndex = lstResults.Items.Count - 1;}catch (Exception ex){MessageBox.Show($"读取数据时出错: {ex.Message}");}finally{btnRead.Enabled = true;}}private async void btnBrowse_Click(object sender, EventArgs e){try{treeNodes.Nodes.Clear();var rootNode = treeNodes.Nodes.Add("Root");// 浏览服务器节点await BrowseNodeAsync("i=84", rootNode); // Objects文件夹通常是i=84}catch (Exception ex){MessageBox.Show($"浏览节点时出错: {ex.Message}");}}private async Task BrowseNodeAsync(string nodeId, TreeNode parentTreeNode){var references = await opcUaClient.BrowseNodeReferenceAsync(nodeId);foreach (var reference in references){var childNode = parentTreeNode.Nodes.Add($"{reference.DisplayName} ({reference.NodeId})");// 如果是文件夹/对象类型,添加一个虚拟子节点以便展开if (reference.NodeClass == Opc.Ua.NodeClass.Object || reference.NodeClass == Opc.Ua.NodeClass.Variable){childNode.Nodes.Add("加载中...");}}}private async void treeNodes_BeforeExpand(object sender, TreeViewCancelEventArgs e){var node = e.Node;// 如果只有一个"加载中..."子节点,则实际加载子节点if (node.Nodes.Count == 1 && node.Nodes[0].Text == "加载中..."){try{node.Nodes.Clear();// 从节点文本中提取NodeIdvar nodeId = ExtractNodeIdFromTreeNode(node);if (!string.IsNullOrEmpty(nodeId)){await BrowseNodeAsync(nodeId, node);}}catch (Exception ex){MessageBox.Show($"加载子节点时出错: {ex.Message}");node.Nodes.Add($"错误: {ex.Message}");}}}private string ExtractNodeIdFromTreeNode(TreeNode node){// 从类似 "DisplayName (ns=2;s=MyVariable)" 的文本中提取 "ns=2;s=MyVariable"var text = node.Text;var start = text.IndexOf('(') + 1;var end = text.IndexOf(')');if (start > 0 && end > start){return text.Substring(start, end - start);}return null;}private void MainForm_FormClosing(object sender, FormClosingEventArgs e){if (isConnected){DisconnectFromServer();}}}
}
3. 功能说明
-
连接/断开服务器:
- 使用
ConnectServerAsync
方法异步连接 - 使用
Disconnect
方法断开连接
- 使用
-
读取节点数据:
- 使用
ReadNodeAsync
方法读取单个节点值 - 支持所有OPC UA数据类型
- 使用
-
浏览服务器节点:
- 使用
BrowseNodeReferenceAsync
方法浏览节点引用 - 实现树形视图的延迟加载
- 使用
-
错误处理:
- 对所有OPC UA操作进行适当的错误处理
4. 扩展功能
你可以根据需要扩展此示例,添加以下功能:
-
写入数据:
await opcUaClient.WriteNodeAsync(nodeId, value);
-
订阅数据变化:
// 创建订阅 var subscription = new OpcUaHelper.Subscription(opcUaClient);// 添加监控项 subscription.AddItem(nodeId);// 数据变化事件 subscription.DataChangeReceived += (s, e) => {// 处理数据变化 };// 启动订阅 await subscription.ApplyAsync();
-
调用方法:
var results = await opcUaClient.CallMethodByNodeIdAsync(objectNodeId, methodNodeId, inputArguments);
5. 注意事项
-
异步编程:所有OPC UA操作都应使用异步方法,避免阻塞UI线程。
-
错误处理:网络操作容易出错,确保有适当的错误处理和用户反馈。
-
安全性:生产环境中可能需要配置安全策略和用户凭据。
-
资源清理:确保在应用程序退出时正确断开连接。