using Newtonsoft.Json.Linq;
using Opc.Ua;
using Opc.Ua.Client;
using Opc.Ua.Export;
using Org.BouncyCastle.Asn1.Ocsp;
using Org.BouncyCastle.Asn1.X509;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using static System.Windows.Forms.VisualStyles.VisualStyleElement;
namespace OpcUaHelper.Forms
{
///
/// 一个浏览OPC服务器节点的窗口类
///
public partial class FormBrowseServer : Form
{
#region Constructor
///
/// 允许自己输入服务器地址的实例化
///
public FormBrowseServer()
{
InitializeComponent();
Icon = ClientUtils.GetAppIcon();
m_typeImageMapping = new Dictionary( );
}
///
/// 固定地址且不允许更改的实例化
///
public FormBrowseServer(string server)
{
InitializeComponent();
Icon = ClientUtils.GetAppIcon();
textBox1.Text = server;
}
#endregion
#region Load Show Close
private void FormBrowseServer_Load(object sender, EventArgs e)
{
BrowseNodesTV.Enabled = false;
BrowseNodesTV.ImageList = new ImageList();
BrowseNodesTV.ImageList.Images.Add("Class_489", Properties.Resources.Class_489);
BrowseNodesTV.ImageList.Images.Add("ClassIcon", Properties.Resources.ClassIcon);
BrowseNodesTV.ImageList.Images.Add("brackets", Properties.Resources.brackets_Square_16xMD);
BrowseNodesTV.ImageList.Images.Add("VirtualMachine", Properties.Resources.VirtualMachine);
BrowseNodesTV.ImageList.Images.Add("Enum_582", Properties.Resources.Enum_582);
BrowseNodesTV.ImageList.Images.Add("Method_636", Properties.Resources.Method_636);
BrowseNodesTV.ImageList.Images.Add("Module_648", Properties.Resources.Module_648);
BrowseNodesTV.ImageList.Images.Add("Loading", Properties.Resources.loading);
// 判断是否允许更改
if (!string.IsNullOrEmpty(textBox1.Text)) textBox1.ReadOnly = true;
// Opc Ua 服务的初始化
OpcUaClientInitialization();
}
private string GetImageKeyFromDescription(ReferenceDescription target, NodeId sourceId)
{
if (target.NodeClass == NodeClass.Variable)
{
DataValue dataValue = m_OpcUaClient.ReadNode((NodeId)target.NodeId);
if (dataValue.WrappedValue.TypeInfo != null)
{
if (dataValue.WrappedValue.TypeInfo.ValueRank == ValueRanks.Scalar)
{
return "Enum_582";
}
else if (dataValue.WrappedValue.TypeInfo.ValueRank == ValueRanks.OneDimension)
{
return "brackets";
}
else if (dataValue.WrappedValue.TypeInfo.ValueRank == ValueRanks.TwoDimensions)
{
return "Module_648";
}
else
{
return "ClassIcon";
}
}
else
{
return "ClassIcon";
}
}
else if (target.NodeClass == NodeClass.Object)
{
if (sourceId == ObjectIds.ObjectsFolder)
{
return "VirtualMachine";
}
else
{
return "ClassIcon";
}
}
else if (target.NodeClass == NodeClass.Method)
{
return "Method_636";
}
else
{
return "ClassIcon";
}
}
private string GetImageIndex( DataValue dataValue )
{
if (dataValue == null) return "ClassIcon";
if (dataValue.WrappedValue.TypeInfo != null)
{
if (dataValue.WrappedValue.TypeInfo.ValueRank == ValueRanks.Scalar)
{
return "Enum_582";
}
else if (dataValue.WrappedValue.TypeInfo.ValueRank == ValueRanks.OneDimension)
{
return "brackets";
}
else if (dataValue.WrappedValue.TypeInfo.ValueRank == ValueRanks.TwoDimensions)
{
return "Module_648";
}
else if (dataValue.WrappedValue.TypeInfo.ValueRank == ValueRanks.OneOrMoreDimensions)
{
return "Module_648";
}
else
{
return "ClassIcon";
}
}
return "ClassIcon";
}
///
/// Returns an image index for the specified attribute.
///
public string GetImageIndex( Session session, NodeClass nodeClass, ExpandedNodeId typeDefinitionId, bool selected, NodeId valueId = null )
{
if (nodeClass == NodeClass.Variable)
{
//if (session.NodeCache.IsTypeOf( typeDefinitionId, Opc.Ua.VariableTypeIds.PropertyType ))
//{
// return "ClassIcon";
//}
if (valueId != null) return GetImageIndex( m_OpcUaClient.ReadNode( valueId ) );
return "ClassIcon";
}
if (nodeClass == NodeClass.Object)
{
if (typeDefinitionId == ObjectIds.ObjectsFolder)
{
return "VirtualMachine";
}
else if (session.NodeCache.IsTypeOf( typeDefinitionId, Opc.Ua.ObjectTypeIds.FolderType ))
{
if (selected)
{
return "ClassIcon";
}
else
{
return "ClassIcon";
}
}
return "ClassIcon";
}
if (nodeClass == NodeClass.Method)
{
return "Method_636";
}
if (nodeClass == NodeClass.View)
{
return "Method_636";
}
return "ClassIcon";
}
private void FormBrowseServer_FormClosing(object sender, FormClosingEventArgs e)
{
m_OpcUaClient.Disconnect();
}
#endregion
#region OPC UA client
///
/// Opc客户端的核心类
///
private OpcUaClient m_OpcUaClient = null;
///
/// 初始化
///
private void OpcUaClientInitialization()
{
m_OpcUaClient = new OpcUaClient();
m_OpcUaClient.OpcStatusChange += M_OpcUaClient_OpcStatusChange1; ;
m_OpcUaClient.ConnectComplete += M_OpcUaClient_ConnectComplete;
}
///
/// 连接服务器结束后马上浏览根节点
///
///
///
private void M_OpcUaClient_ConnectComplete(object sender, EventArgs e)
{
//try
//{
// OpcUaClient client = (OpcUaClient)sender;
// if (client.Connected)
// {
// // populate the browse view.
// PopulateBranch(ObjectIds.ObjectsFolder, BrowseNodesTV.Nodes);
// BrowseNodesTV.Enabled = true;
// }
//}
//catch (Exception exception)
//{
// ClientUtils.HandleException(Text, exception);
//}
try
{
m_session = m_OpcUaClient.Session as Opc.Ua.Client.Session;
// set a suitable initial state.
if (m_session != null)
{
BrowseDescription nodeToBrowse = new BrowseDescription( );
nodeToBrowse.NodeId = Opc.Ua.ObjectIds.ViewsFolder;
nodeToBrowse.ReferenceTypeId = Opc.Ua.ReferenceTypeIds.HierarchicalReferences;
nodeToBrowse.IncludeSubtypes = true;
nodeToBrowse.BrowseDirection = BrowseDirection.Forward;
nodeToBrowse.NodeClassMask = 0;
nodeToBrowse.ResultMask = (uint)BrowseResultMask.All;
ReferenceDescriptionCollection references = ClientUtils.Browse( m_session, nodeToBrowse, false );
}
// browse the instances in the server.
Initialize( m_session, ObjectIds.ObjectsFolder, ReferenceTypeIds.Organizes, ReferenceTypeIds.Aggregates );
BrowseNodesTV.Enabled = true;
}
catch (Exception exception)
{
ClientUtils.HandleException( this.Text, exception );
}
}
///
/// OPC 客户端的状态变化后的消息提醒
///
///
///
private void M_OpcUaClient_OpcStatusChange1(object sender, OpcUaStatusEventArgs e)
{
if (InvokeRequired)
{
BeginInvoke(new Action(() =>
{
M_OpcUaClient_OpcStatusChange1(sender, e);
}));
return;
}
if (e.Error)
{
toolStripStatusLabel1.BackColor = Color.Red;
}
else
{
toolStripStatusLabel1.BackColor = SystemColors.Control;
}
toolStripStatusLabel_opc.Text = e.ToString();
}
private ReferenceDescriptionCollection GetReferenceDescriptionCollection(NodeId sourceId)
{
TaskCompletionSource task = new TaskCompletionSource();
// find all of the components of the node.
BrowseDescription nodeToBrowse1 = new BrowseDescription();
nodeToBrowse1.NodeId = sourceId;
nodeToBrowse1.BrowseDirection = BrowseDirection.Forward;
nodeToBrowse1.ReferenceTypeId = ReferenceTypeIds.Aggregates;
nodeToBrowse1.IncludeSubtypes = true;
nodeToBrowse1.NodeClassMask = (uint)(NodeClass.Object | NodeClass.Variable | NodeClass.Method | NodeClass.ReferenceType | NodeClass.ObjectType | NodeClass.View | NodeClass.VariableType | NodeClass.DataType);
nodeToBrowse1.ResultMask = (uint)BrowseResultMask.All;
// find all nodes organized by the node.
BrowseDescription nodeToBrowse2 = new BrowseDescription();
nodeToBrowse2.NodeId = sourceId;
nodeToBrowse2.BrowseDirection = BrowseDirection.Forward;
nodeToBrowse2.ReferenceTypeId = ReferenceTypeIds.Organizes;
nodeToBrowse2.IncludeSubtypes = true;
nodeToBrowse2.NodeClassMask = (uint)(NodeClass.Object | NodeClass.Variable | NodeClass.Method | NodeClass.View | NodeClass.ReferenceType | NodeClass.ObjectType | NodeClass.VariableType | NodeClass.DataType);
nodeToBrowse2.ResultMask = (uint)BrowseResultMask.All;
BrowseDescriptionCollection nodesToBrowse = new BrowseDescriptionCollection();
nodesToBrowse.Add(nodeToBrowse1);
nodesToBrowse.Add(nodeToBrowse2);
// fetch references from the server.
ReferenceDescriptionCollection references = FormUtils.Browse(m_OpcUaClient.Session, nodesToBrowse, false);
return references;
}
///
/// 0:NodeClass 1:Value 2:AccessLevel 3:DisplayName 4:Description
///
///
///
private DataValue[] ReadOneNodeFiveAttributes(List nodeIds)
{
ReadValueIdCollection nodesToRead = new ReadValueIdCollection();
foreach (var nodeId in nodeIds)
{
NodeId sourceId = nodeId;
nodesToRead.Add(new ReadValueId()
{
NodeId = sourceId,
AttributeId = Attributes.NodeClass
});
nodesToRead.Add(new ReadValueId()
{
NodeId = sourceId,
AttributeId = Attributes.Value
});
nodesToRead.Add(new ReadValueId()
{
NodeId = sourceId,
AttributeId = Attributes.AccessLevel
});
nodesToRead.Add(new ReadValueId()
{
NodeId = sourceId,
AttributeId = Attributes.DisplayName
});
nodesToRead.Add(new ReadValueId()
{
NodeId = sourceId,
AttributeId = Attributes.Description
});
}
// read all values.
m_OpcUaClient.Session.Read(
null,
0,
TimestampsToReturn.Neither,
nodesToRead,
out DataValueCollection results,
out DiagnosticInfoCollection diagnosticInfos);
ClientBase.ValidateResponse(results, nodesToRead);
ClientBase.ValidateDiagnosticInfos(diagnosticInfos, nodesToRead);
return results.ToArray();
}
///
/// 读取一个节点的指定属性
///
///
///
///
private DataValue ReadNoteDataValueAttributes(NodeId nodeId, uint attribute)
{
NodeId sourceId = nodeId;
ReadValueIdCollection nodesToRead = new ReadValueIdCollection();
ReadValueId nodeToRead = new ReadValueId();
nodeToRead.NodeId = sourceId;
nodeToRead.AttributeId = attribute;
nodesToRead.Add(nodeToRead);
int startOfProperties = nodesToRead.Count;
// find all of the pror of the node.
BrowseDescription nodeToBrowse1 = new BrowseDescription();
nodeToBrowse1.NodeId = sourceId;
nodeToBrowse1.BrowseDirection = BrowseDirection.Forward;
nodeToBrowse1.ReferenceTypeId = ReferenceTypeIds.HasProperty;
nodeToBrowse1.IncludeSubtypes = true;
nodeToBrowse1.NodeClassMask = 0;
nodeToBrowse1.ResultMask = (uint)BrowseResultMask.All;
BrowseDescriptionCollection nodesToBrowse = new BrowseDescriptionCollection();
nodesToBrowse.Add(nodeToBrowse1);
// fetch property references from the server.
ReferenceDescriptionCollection references = FormUtils.Browse(m_OpcUaClient.Session, nodesToBrowse, false);
if (references == null)
{
return null;
}
for (int ii = 0; ii < references.Count; ii++)
{
// ignore external references.
if (references[ii].NodeId.IsAbsolute)
{
continue;
}
ReadValueId nodeToRead2 = new ReadValueId();
nodeToRead2.NodeId = (NodeId)references[ii].NodeId;
nodeToRead2.AttributeId = Attributes.Value;
nodesToRead.Add(nodeToRead2);
}
// read all values.
DataValueCollection results = null;
DiagnosticInfoCollection diagnosticInfos = null;
m_OpcUaClient.Session.Read(
null,
0,
TimestampsToReturn.Neither,
nodesToRead,
out results,
out diagnosticInfos);
ClientBase.ValidateResponse(results, nodesToRead);
ClientBase.ValidateDiagnosticInfos(diagnosticInfos, nodesToRead);
return results[0];
}
#endregion
#region Menu Click Event
private void exitToolStripMenuItem_Click(object sender, EventArgs e)
{
// press exit menu button
Close();
}
private void discoverToolStripMenuItem_Click(object sender, EventArgs e)
{
string endpointUrl = new DiscoverServerDlg().ShowDialog(m_OpcUaClient.AppConfig, null);
if (endpointUrl != null)
{
textBox1.Text = endpointUrl;
}
}
#endregion
#region Press Connect Click Button
private async void button1_Click( object sender, EventArgs e )
{
// connect to server
using (FormConnectSelect formConnectSelect = new FormConnectSelect( m_OpcUaClient ))
{
if (formConnectSelect.ShowDialog( ) == DialogResult.OK)
{
try
{
await m_OpcUaClient.ConnectServer( textBox1.Text );
button1.Enabled = false;
button3.Enabled = true;
}
catch (Exception ex)
{
ClientUtils.HandleException( Text, ex );
}
}
}
}
private void button3_Click( object sender, EventArgs e )
{
// 关闭连接
try
{
m_OpcUaClient?.Disconnect( );
button1.Enabled = true;
button3.Enabled = false;
}
catch (Exception ex)
{
ClientUtils.HandleException( Text, ex );
}
}
#endregion
#region 填入分支
///
/// Populates the branch in the tree view.
///
/// The NodeId of the Node to browse.
/// The node collect to populate.
private async void PopulateBranch(NodeId sourceId, TreeNodeCollection nodes)
{
nodes.Clear();
nodes.Add(new TreeNode("Browsering...", 7, 7));
// fetch references from the server.
TreeNode[] listNode = await Task.Run(() =>
{
ReferenceDescriptionCollection references = GetReferenceDescriptionCollection(sourceId);
List list = new List();
if (references != null)
{
// process results.
for (int ii = 0; ii < references.Count; ii++)
{
ReferenceDescription target = references[ii];
TreeNode child = new TreeNode(Utils.Format("{0}", target));
child.Tag = target;
string key = GetImageKeyFromDescription(target, sourceId);
child.ImageKey = key;
child.SelectedImageKey = key;
// if (target.NodeClass == NodeClass.Object || target.NodeClass == NodeClass.Unspecified || expanded)
// {
// child.Nodes.Add(new TreeNode());
// }
if (!checkBox1.Checked)
{
if (GetReferenceDescriptionCollection( (NodeId)target.NodeId ).Count > 0)
{
child.Nodes.Add( new TreeNode( ) );
}
}
else
{
child.Nodes.Add( new TreeNode( ) );
}
list.Add(child);
}
}
return list.ToArray();
});
// update the attributes display.
// DisplayAttributes(sourceId);
nodes.Clear();
nodes.AddRange(listNode.ToArray());
}
#endregion
#region 节点打开的时候操作
private void BrowseNodesTV_MouseClick(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Right)
{
TreeNode tn = BrowseNodesTV.GetNodeAt(e.X, e.Y);
if (tn != null)
{
BrowseNodesTV.SelectedNode = tn;
}
}
}
private async void BrowseNodesTV_BeforeExpand(object sender, TreeViewCancelEventArgs e)
{
//try
//{
// check if node has already been expanded once.
if (e.Node.Nodes.Count != 1)
{
//return;
}
if (e.Node.Nodes.Count > 0)
{
if (e.Node.Nodes[0].Text != String.Empty)
{
return;
}
}
// // populate children.
// PopulateBranch((NodeId)reference.NodeId, e.Node.Nodes);
//}
//catch (Exception exception)
//{
// ClientUtils.HandleException(this.Text, exception);
//}
BrowseTV_BeforeExpand( sender, e );
}
private void BrowseNodesTV_AfterSelect(object sender, TreeViewEventArgs e)
{
try
{
RemoveAllSubscript( );
// get the source for the node.
ReferenceDescription reference = e.Node.Tag as ReferenceDescription;
if (reference == null || reference.NodeId.IsAbsolute)
{
return;
}
// populate children.
ShowMember((NodeId)reference.NodeId);
}
catch (Exception exception)
{
ClientUtils.HandleException(Text, exception);
}
}
private void ClearDataGridViewRows(int index)
{
for (int i = dataGridView1.Rows.Count - 1; i >= index; i--)
{
if (i >= 0)
{
dataGridView1.Rows.RemoveAt(i);
}
}
}
#endregion
#region 点击树节点后在数据表显示
///
/// 点击了节点名称前的内容进行复制
///
///
///
private void label2_Click(object sender, EventArgs e)
{
if (!string.IsNullOrEmpty(textBox_nodeId.Text))
{
Clipboard.SetText(textBox_nodeId.Text);
}
}
private async void ShowMember(NodeId sourceId)
{
textBox_nodeId.Text = sourceId.ToString();
// dataGridView1.Rows.Clear();
int index = 0;
ReferenceDescriptionCollection references;
try
{
references = await Task.Run(() =>
{
return GetReferenceDescriptionCollection(sourceId);
});
}
catch(Exception exception)
{
ClientUtils.HandleException(Text, exception);
return;
}
if (references?.Count > 0)
{
// 获取所有要读取的子节点
List nodeIds = new List();
for (int ii = 0; ii < references.Count; ii++)
{
ReferenceDescription target = references[ii];
nodeIds.Add((NodeId)target.NodeId);
}
DateTime dateTimeStart = DateTime.Now;
// 获取所有的值
DataValue[] dataValues = await Task.Run(() =>
{
return ReadOneNodeFiveAttributes(nodeIds);
});
label_time_spend.Text = (int)(DateTime.Now - dateTimeStart).TotalMilliseconds + " ms";
// 显示
for (int jj = 0; jj < dataValues.Length; jj += 5)
{
AddDataGridViewNewRow(dataValues, jj, index++, nodeIds[jj / 5]);
}
}
else
{
// 子节点没有数据的情况
try
{
DateTime dateTimeStart = DateTime.Now;
DataValue dataValue = m_OpcUaClient.ReadNode(sourceId);
if (dataValue.WrappedValue.TypeInfo?.ValueRank == ValueRanks.OneDimension)
{
// 数组显示
AddDataGridViewArrayRow(sourceId, out index);
}
else
{
// 显示单个数本身
label_time_spend.Text = (int)(DateTime.Now - dateTimeStart).TotalMilliseconds + " ms";
AddDataGridViewNewRow(ReadOneNodeFiveAttributes(new List() { sourceId }), 0, index++, sourceId);
}
}
catch (Exception exception)
{
ClientUtils.HandleException(Text, exception);
return;
}
}
ClearDataGridViewRows(index);
}
private void AddDataGridViewNewRow(DataValue[] dataValues, int startIndex, int index, NodeId nodeId)
{
// int index = dataGridView1.Rows.Add();
while (index >= dataGridView1.Rows.Count)
{
dataGridView1.Rows.Add();
}
DataGridViewRow dgvr = dataGridView1.Rows[index];
dgvr.Tag = nodeId;
if (dataValues[startIndex].WrappedValue.Value == null) return;
NodeClass nodeclass = (NodeClass)dataValues[startIndex].WrappedValue.Value;
dgvr.Cells[1].Value = dataValues[3 + startIndex].WrappedValue.Value;
dgvr.Cells[5].Value = dataValues[4 + startIndex].WrappedValue.Value;
dgvr.Cells[4].Value = GetDiscriptionFromAccessLevel(dataValues[2 + startIndex]);
if (nodeclass == NodeClass.Object)
{
dgvr.Cells[0].Value = Properties.Resources.ClassIcon;
dgvr.Cells[2].Value = "";
dgvr.Cells[3].Value = nodeclass.ToString();
}
else if (nodeclass == NodeClass.Method)
{
dgvr.Cells[0].Value = Properties.Resources.Method_636;
dgvr.Cells[2].Value = "";
dgvr.Cells[3].Value = nodeclass.ToString();
}
else if (nodeclass == NodeClass.Variable)
{
DataValue dataValue = dataValues[1 + startIndex];
if (dataValue.WrappedValue.TypeInfo != null)
{
dgvr.Cells[3].Value = dataValue.WrappedValue.TypeInfo.BuiltInType;
dgvr.Cells[6].Value = dataValue.StatusCode.ToString();
// dgvr.Cells[3].Value = dataValue.Value.GetType().ToString();
if (dataValue.WrappedValue.TypeInfo.ValueRank == ValueRanks.Scalar)
{
dgvr.Cells[2].Value = dataValue.WrappedValue.Value;
dgvr.Cells[0].Value = Properties.Resources.Enum_582;
}
else if (dataValue.WrappedValue.TypeInfo.ValueRank == ValueRanks.OneDimension)
{
dgvr.Cells[2].Value = dataValue.Value.GetType().ToString();
dgvr.Cells[0].Value = Properties.Resources.brackets_Square_16xMD;
}
else if (dataValue.WrappedValue.TypeInfo.ValueRank == ValueRanks.TwoDimensions)
{
dgvr.Cells[2].Value = dataValue.Value.GetType().ToString();
dgvr.Cells[0].Value = Properties.Resources.Module_648;
}
else
{
dgvr.Cells[2].Value = dataValue.Value.GetType().ToString();
dgvr.Cells[0].Value = Properties.Resources.ClassIcon;
}
}
else
{
dgvr.Cells[0].Value = Properties.Resources.ClassIcon;
dgvr.Cells[2].Value = dataValue.Value;
dgvr.Cells[3].Value = "null";
}
}
else
{
dgvr.Cells[2].Value = "";
dgvr.Cells[0].Value = Properties.Resources.ClassIcon;
dgvr.Cells[3].Value = nodeclass.ToString();
dgvr.Cells[6].Value = "";
}
}
private void AddDataGridViewArrayRow(NodeId nodeId,out int index)
{
DateTime dateTimeStart = DateTime.Now;
DataValue[] dataValues = ReadOneNodeFiveAttributes(new List() { nodeId });
label_time_spend.Text = (int)(DateTime.Now - dateTimeStart).TotalMilliseconds + " ms";
DataValue dataValue = dataValues[1];
if (dataValue.WrappedValue.TypeInfo?.ValueRank == ValueRanks.OneDimension)
{
string access= GetDiscriptionFromAccessLevel(dataValues[2]);
BuiltInType type = dataValue.WrappedValue.TypeInfo.BuiltInType;
object des = dataValues[4].Value ?? "";
object dis = dataValues[3].Value ?? type;
Array array = dataValue.Value as Array;
int i = 0;
foreach(object obj in array)
{
while (i >= dataGridView1.Rows.Count)
{
dataGridView1.Rows.Add();
}
DataGridViewRow dgvr = dataGridView1.Rows[i];
dgvr.Tag = null;
dgvr.Cells[0].Value = Properties.Resources.Enum_582;
dgvr.Cells[1].Value = $"{dis} [{i++}]";
dgvr.Cells[2].Value = obj;
dgvr.Cells[3].Value = type;
dgvr.Cells[4].Value = access;
dgvr.Cells[5].Value = des;
}
index = i;
}
else
{
index = 0;
}
}
private string GetDiscriptionFromAccessLevel(DataValue value)
{
if (value.WrappedValue.Value != null)
{
switch ((byte)value.WrappedValue.Value)
{
case 0: return "None";
case 1: return "CurrentRead";
case 2: return "CurrentWrite";
case 3: return "CurrentReadOrWrite";
case 4: return "HistoryRead";
case 8: return "HistoryWrite";
case 12: return "HistoryReadOrWrite";
case 16: return "SemanticChange";
case 32: return "StatusWrite";
case 64: return "TimestampWrite";
default: return "None";
}
}
else
{
return "null";
}
}
#endregion
#region 订阅刷新块
private List subNodeIds = new List( );
private bool isSingleValueSub = false;
private void RemoveAllSubscript( )
{
m_OpcUaClient?.RemoveAllSubscription( );
}
private void SubCallBack( string key, MonitoredItem monitoredItem, MonitoredItemNotificationEventArgs eventArgs )
{
if (InvokeRequired)
{
Invoke( new Action( SubCallBack ), key, monitoredItem, eventArgs );
return;
}
MonitoredItemNotification notification = eventArgs.NotificationValue as MonitoredItemNotification;
string nodeId = monitoredItem.StartNodeId.ToString( );
int index = subNodeIds.IndexOf( nodeId );
if (index >= 0)
{
if (isSingleValueSub)
{
if (notification.Value.WrappedValue.TypeInfo?.ValueRank == ValueRanks.OneDimension)
{
Array array = notification.Value.WrappedValue.Value as Array;
int i = 0;
foreach (object obj in array)
{
DataGridViewRow dgvr = dataGridView1.Rows[i];
dgvr.Cells[2].Value = obj;
i++;
}
}
else
{
dataGridView1.Rows[index].Cells[2].Value = notification.Value.WrappedValue.Value;
}
}
else
{
dataGridView1.Rows[index].Cells[2].Value = notification.Value.WrappedValue.Value;
}
}
}
private async void button2_Click(object sender, EventArgs e)
{
if (m_OpcUaClient != null)
{
RemoveAllSubscript( );
if (button2.BackColor != Color.LimeGreen)
{
button2.BackColor = Color.LimeGreen;
// 判断当前的选择
if (string.IsNullOrEmpty( textBox_nodeId.Text )) return;
ReferenceDescriptionCollection references;
try
{
references = await Task.Run( ( ) =>
{
return GetReferenceDescriptionCollection( new NodeId( textBox_nodeId.Text ) );
} );
}
catch (Exception exception)
{
ClientUtils.HandleException( Text, exception );
return;
}
subNodeIds = new List( );
if (references?.Count > 0)
{
isSingleValueSub = false;
// 获取所有要订阅的子节点
for (int ii = 0; ii < references.Count; ii++)
{
ReferenceDescription target = references[ii];
subNodeIds.Add( ((NodeId)target.NodeId).ToString( ) );
}
}
else
{
isSingleValueSub = true;
// 子节点没有数据的情况
subNodeIds.Add( textBox_nodeId.Text );
}
m_OpcUaClient.AddSubscription( "subTest", subNodeIds.ToArray( ), SubCallBack );
}
else
{
button2.BackColor = SystemColors.Control;
}
}
}
#endregion
#region 点击了表格修改数据
private void dataGridView1_CellEndEdit(object sender, DataGridViewCellEventArgs e)
{
if (dataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex + 1].Value is BuiltInType builtInType)
{
dynamic value = null;
if (dataGridView1.Rows[e.RowIndex].Tag is NodeId nodeId)
{
// 节点
try
{
value = GetValueFromString(dataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex].Value.ToString(), builtInType);
}
catch
{
MessageBox.Show("Invalid Input Value");
return;
}
if (!m_OpcUaClient.WriteNode(nodeId.ToString(), value))
{
MessageBox.Show("Failed to write value");
}
}
else
{
// 点击了数组修改
IList list = new List();
for (int jj = 0; jj < dataGridView1.RowCount; jj++)
{
list.Add(dataGridView1.Rows[jj].Cells[e.ColumnIndex].Value.ToString());
}
try
{
value = GetArrayValueFromString(list, builtInType);
}
catch(Exception ex)
{
MessageBox.Show("Invalid Input Value: " + ex.Message);
return;
}
if (!m_OpcUaClient.WriteNode(textBox_nodeId.Text, value))
{
MessageBox.Show("Failed to write value");
}
}
}
else
{
MessageBox.Show("Invalid data type");
}
//MessageBox.Show(
// "Type:" + dataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex].Value.GetType().ToString() + Environment.NewLine +
// "Value:" + dataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex].Value.ToString());
}
private dynamic GetValueFromString(string value, BuiltInType builtInType)
{
switch(builtInType)
{
case BuiltInType.Boolean:
{
return bool.Parse(value);
}
case BuiltInType.Byte:
{
return byte.Parse(value);
}
case BuiltInType.DateTime:
{
return DateTime.Parse(value);
}
case BuiltInType.Double:
{
return double.Parse(value);
}
case BuiltInType.Float:
{
return float.Parse(value);
}
case BuiltInType.Guid:
{
return Guid.Parse(value);
}
case BuiltInType.Int16:
{
return short.Parse(value);
}
case BuiltInType.Int32:
{
return int.Parse(value);
}
case BuiltInType.Int64:
{
return long.Parse(value);
}
case BuiltInType.Integer:
{
return int.Parse(value);
}
case BuiltInType.LocalizedText:
{
return value;
}
case BuiltInType.SByte:
{
return sbyte.Parse(value);
}
case BuiltInType.String:
{
return value;
}
case BuiltInType.UInt16:
{
return ushort.Parse(value);
}
case BuiltInType.UInt32:
{
return uint.Parse(value);
}
case BuiltInType.UInt64:
{
return ulong.Parse(value);
}
case BuiltInType.UInteger:
{
return uint.Parse(value);
}
default:throw new Exception("Not supported data type");
}
}
private dynamic GetArrayValueFromString(IList values, BuiltInType builtInType)
{
switch (builtInType)
{
case BuiltInType.Boolean:
{
bool[] result = new bool[values.Count];
for (int i = 0; i < values.Count; i++)
{
result[i] = bool.Parse(values[i]);
}
return result;
}
case BuiltInType.Byte:
{
byte[] result = new byte[values.Count];
for (int i = 0; i < values.Count; i++)
{
result[i] = byte.Parse(values[i]);
}
return result;
}
case BuiltInType.DateTime:
{
DateTime[] result = new DateTime[values.Count];
for (int i = 0; i < values.Count; i++)
{
result[i] = DateTime.Parse(values[i]);
}
return result;
}
case BuiltInType.Double:
{
double[] result = new double[values.Count];
for (int i = 0; i < values.Count; i++)
{
result[i] = double.Parse(values[i]);
}
return result;
}
case BuiltInType.Float:
{
float[] result = new float[values.Count];
for (int i = 0; i < values.Count; i++)
{
result[i] = float.Parse(values[i]);
}
return result;
}
case BuiltInType.Guid:
{
Guid[] result = new Guid[values.Count];
for (int i = 0; i < values.Count; i++)
{
result[i] = Guid.Parse(values[i]);
}
return result;
}
case BuiltInType.Int16:
{
short[] result = new short[values.Count];
for (int i = 0; i < values.Count; i++)
{
result[i] = short.Parse(values[i]);
}
return result;
}
case BuiltInType.Int32:
{
int[] result = new int[values.Count];
for (int i = 0; i < values.Count; i++)
{
result[i] = int.Parse(values[i]);
}
return result;
}
case BuiltInType.Int64:
{
long[] result = new long[values.Count];
for (int i = 0; i < values.Count; i++)
{
result[i] = long.Parse(values[i]);
}
return result;
}
case BuiltInType.Integer:
{
int[] result = new int[values.Count];
for (int i = 0; i < values.Count; i++)
{
result[i] = int.Parse(values[i]);
}
return result;
}
case BuiltInType.LocalizedText:
{
return values.ToArray();
}
case BuiltInType.SByte:
{
sbyte[] result = new sbyte[values.Count];
for (int i = 0; i < values.Count; i++)
{
result[i] = sbyte.Parse(values[i]);
}
return result;
}
case BuiltInType.String:
{
return values.ToArray();
}
case BuiltInType.UInt16:
{
ushort[] result = new ushort[values.Count];
for (int i = 0; i < values.Count; i++)
{
result[i] = ushort.Parse(values[i]);
}
return result;
}
case BuiltInType.UInt32:
{
uint[] result = new uint[values.Count];
for (int i = 0; i < values.Count; i++)
{
result[i] = uint.Parse(values[i]);
}
return result;
}
case BuiltInType.UInt64:
{
ulong[] result = new ulong[values.Count];
for (int i = 0; i < values.Count; i++)
{
result[i] = ulong.Parse(values[i]);
}
return result;
}
case BuiltInType.UInteger:
{
uint[] result = new uint[values.Count];
for (int i = 0; i < values.Count; i++)
{
result[i] = uint.Parse(values[i]);
}
return result;
}
default: throw new Exception("Not supported data type");
}
}
private void dataGridView1_CellBeginEdit(object sender, DataGridViewCellCancelEventArgs e)
{
if (dataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex + 1].Value is BuiltInType builtInType)
{
if (
builtInType == BuiltInType.Boolean ||
builtInType == BuiltInType.Byte ||
builtInType == BuiltInType.DateTime ||
builtInType == BuiltInType.Double ||
builtInType == BuiltInType.Float ||
builtInType == BuiltInType.Guid ||
builtInType == BuiltInType.Int16 ||
builtInType == BuiltInType.Int32 ||
builtInType == BuiltInType.Int64 ||
builtInType == BuiltInType.Integer ||
builtInType == BuiltInType.LocalizedText ||
builtInType == BuiltInType.SByte ||
builtInType == BuiltInType.String ||
builtInType == BuiltInType.UInt16 ||
builtInType == BuiltInType.UInt32 ||
builtInType == BuiltInType.UInt64 ||
builtInType == BuiltInType.UInteger
)
{
}
else
{
e.Cancel = true;
MessageBox.Show("Not support the Type of modify value!");
return;
}
}
else
{
e.Cancel = true;
MessageBox.Show("Not support the Type of modify value!");
return;
}
if (!dataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex + 2].Value.ToString().Contains("Write"))
{
e.Cancel = true;
MessageBox.Show("Not support the access of modify value!");
}
}
#endregion
#region Browser New Method
private NodeId[] m_referenceTypeIds;
private NodeId m_rootId;
private Session m_session;
private Dictionary m_typeImageMapping;
private ViewDescription m_view;
///
/// The view to use.
///
public ViewDescription View
{
get
{
return m_view;
}
set
{
m_view = value;
}
}
///
/// Initializes the control with a root and a set of hierarchial reference types to follow.
///
/// The session.
/// The root of the hierarchy to browse.
/// The reference types to follow.
public void Initialize(
Session session,
NodeId rootId,
params NodeId[] referenceTypeIds )
{
// set default root.
if (NodeId.IsNull( rootId ))
{
rootId = Opc.Ua.ObjectIds.ObjectsFolder;
}
// set default reference type.
if (referenceTypeIds == null)
{
referenceTypeIds = new NodeId[] { Opc.Ua.ReferenceTypeIds.HierarchicalReferences };
}
m_rootId = rootId;
m_referenceTypeIds = referenceTypeIds;
// save session.
ChangeSession( session, true );
}
///
/// Changes the session used by the control.
///
private void ChangeSession( Session session, bool refresh )
{
m_session = session;
BrowseNodesTV.Nodes.Clear( );
if (m_session != null)
{
INode node = m_session.NodeCache.Find( m_rootId );
if (node != null)
{
TreeNode root = new TreeNode( node.ToString( ) );
root.ImageKey = GetImageIndex( m_session, node.NodeClass, node.TypeDefinitionId, false );
root.SelectedImageKey = GetImageIndex( m_session, node.NodeClass, node.TypeDefinitionId, true );
ReferenceDescription reference = new ReferenceDescription( );
reference.NodeId = node.NodeId;
reference.NodeClass = node.NodeClass;
reference.BrowseName = node.BrowseName;
reference.DisplayName = node.DisplayName;
reference.TypeDefinition = node.TypeDefinitionId;
root.Tag = reference;
root.Nodes.Add( new TreeNode( ) );
BrowseNodesTV.Nodes.Add( root );
root.Expand( );
BrowseNodesTV.SelectedNode = root;
}
}
}
///
/// Handles the BeforeExpand event of the BrowseTV control.
///
private async Task BrowseTV_BeforeExpand( object sender, TreeViewCancelEventArgs e )
{
try
{
e.Node.Nodes.Clear( );
e.Node.Nodes.Add( new TreeNode( "Browsering...", 7, 7 ) );
TreeNode[] listNode = await Task.Run( ( ) =>
{
Console.WriteLine( "BrowseTV_BeforeExpand, m_referenceTypeIds length: " + m_referenceTypeIds.Length );
ReferenceDescription reference = (ReferenceDescription)e.Node.Tag;
// build list of references to browse.
BrowseDescriptionCollection nodesToBrowse = new BrowseDescriptionCollection( );
for (int ii = 0; ii < m_referenceTypeIds.Length; ii++)
{
BrowseDescription nodeToBrowse = new BrowseDescription( );
nodeToBrowse.NodeId = m_rootId;
nodeToBrowse.BrowseDirection = BrowseDirection.Forward;
nodeToBrowse.ReferenceTypeId = m_referenceTypeIds[ii];
nodeToBrowse.IncludeSubtypes = true;
nodeToBrowse.NodeClassMask = 0;
nodeToBrowse.ResultMask = (uint)BrowseResultMask.All;
if (reference != null)
{
nodeToBrowse.NodeId = (NodeId)reference.NodeId;
}
nodesToBrowse.Add( nodeToBrowse );
}
// add the childen to the control.
SortedDictionary dictionary = new SortedDictionary( );
Console.WriteLine( " ClientUtils.Browse... " );
ReferenceDescriptionCollection references = ClientUtils.Browse( m_session, View, nodesToBrowse, false );
Console.WriteLine( " ClientUtils.Browse: " + (references == null ? "NULL" : "Count:" + references.Count) );
for (int ii = 0; references != null && ii < references.Count; ii++)
{
reference = references[ii];
// ignore out of server references.
if (reference.NodeId.IsAbsolute)
{
continue;
}
if (dictionary.ContainsKey( reference.NodeId ))
{
continue;
}
TreeNode child = new TreeNode( reference.ToString( ) );
if (!checkBox1.Checked)
{
if (GetReferenceDescriptionCollection( (NodeId)reference.NodeId ).Count > 0)
{
child.Nodes.Add( new TreeNode( ) );
}
}
else
{
child.Nodes.Add( new TreeNode( ) );
}
child.Tag = reference;
if (!reference.TypeDefinition.IsAbsolute)
{
try
{
if (!m_typeImageMapping.ContainsKey( (NodeId)reference.TypeDefinition ))
{
DataValue value = m_session.ReadValue( (NodeId)reference.NodeId );
m_typeImageMapping[(NodeId)reference.TypeDefinition] = GetImageIndex( value );
}
}
catch (Exception exception)
{
Utils.LogError( exception, "Error loading image." );
}
}
string index = "ClassIcon";
if (!m_typeImageMapping.TryGetValue( (NodeId)reference.TypeDefinition, out index ))
{
child.ImageKey = GetImageIndex( m_session, reference.NodeClass, reference.TypeDefinition, false );
child.SelectedImageKey = GetImageIndex( m_session, reference.NodeClass, reference.TypeDefinition, true );
}
else
{
child.ImageKey = index;
child.SelectedImageKey = index;
}
dictionary[reference.NodeId] = child;
}
// add nodes to tree.
List list = new List( );
foreach (TreeNode node in dictionary.Values)
{
list.Add( node );
}
return list.ToArray( );
} );
e.Node.Nodes.Clear( );
e.Node.Nodes.AddRange( listNode.ToArray( ) );
}
catch (Exception exception)
{
ClientUtils.HandleException( this.Text, exception );
}
if (checkBox2.Checked)
{
await Task.Run( ( ) =>
{
List list = new List( );
foreach (TreeNode node in e.Node.Nodes)
{
if (node.Tag is ReferenceDescription reference)
{
list.Add( new TreeNodeOpcValue( ) { Node = node, NodeId = (NodeId)reference.NodeId } );
}
}
try
{
m_session.ReadValues( list.Select( m => m.NodeId ).ToList( ), out DataValueCollection collections, out IList errors );
Invoke( new Action( ( ) =>
{
for (int i = 0; i < list.Count; i++)
{
if (Opc.Ua.StatusCode.IsGood( errors[i].StatusCode ))
{
list[i].Value = collections[i];
list[i].Node.ImageKey = GetImageIndex( collections[i] );
list[i].Node.SelectedImageKey = GetImageIndex( collections[i] );
}
}
} ) );
}
catch (Exception ex)
{
Utils.Trace( ex, "Error loading image." );
}
} );
}
}
#endregion
}
public class TreeNodeOpcValue
{
public TreeNode Node { get; set; }
public NodeId NodeId { get; set; }
public DataValue Value { get; set; }
}
}