/// <summary> /// Retrieves the data types in the dictionary. /// </summary> /// <remarks> /// In order to allow for fast Linq matching of dictionary /// QNames with the data type nodes, the BrowseName of /// the DataType node is replaced with Value string. /// </remarks> private void ReadDataTypes(NodeId dictionaryId) { Browser browser = new Browser(m_session); browser.BrowseDirection = BrowseDirection.Forward; browser.ReferenceTypeId = ReferenceTypeIds.HasComponent; browser.IncludeSubtypes = false; browser.NodeClassMask = 0; ReferenceDescriptionCollection references = browser.Browse(dictionaryId); foreach (ReferenceDescription reference in references) { NodeId datatypeId = ExpandedNodeId.ToNodeId(reference.NodeId, m_session.NamespaceUris); if (datatypeId != null) { // read the value to get the name that is used in the dictionary var value = m_session.ReadValue(datatypeId); var dictName = (String)value.Value; // replace the BrowseName with type name used in the dictionary reference.BrowseName = new QualifiedName(dictName, datatypeId.NamespaceIndex); DataTypes[datatypeId] = reference; } } }
/// <summary> /// Retrieves the type system for the dictionary. /// </summary> private void GetTypeSystem(NodeId dictionaryId) { Browser browser = new Browser(m_session); browser.BrowseDirection = BrowseDirection.Inverse; browser.ReferenceTypeId = ReferenceTypeIds.HasComponent; browser.IncludeSubtypes = false; browser.NodeClassMask = 0; ReferenceDescriptionCollection references = browser.Browse(dictionaryId); if (references.Count > 0) { m_typeSystemId = ExpandedNodeId.ToNodeId(references[0].NodeId, m_session.NamespaceUris); m_typeSystemName = references[0].ToString(); } }
/// <summary> /// Retrieves the data types in the dictionary. /// </summary> private void ReadDataTypes(NodeId dictionaryId) { Browser browser = new Browser(m_session); browser.BrowseDirection = BrowseDirection.Forward; browser.ReferenceTypeId = ReferenceTypeIds.HasComponent; browser.IncludeSubtypes = false; browser.NodeClassMask = 0; ReferenceDescriptionCollection references = browser.Browse(dictionaryId); foreach (ReferenceDescription reference in references) { NodeId datatypeId = ExpandedNodeId.ToNodeId(reference.NodeId, m_session.NamespaceUris); if (datatypeId != null) { m_datatypes[datatypeId] = reference; } } }
private bool IsValidNode(NodeId nodeId, string nodeName, OPCAEBROWSETYPE dwBrowseFilterType) { Browser browse = new Browser(m_session); ReferenceDescriptionCollection references = null; try { // For a node to be an area, it has to have the 'HasNotifier' reference and must // allow event notification (the EventNotifier attribute is set to SubscribeToEvents) if (dwBrowseFilterType == OPCAEBROWSETYPE.OPC_AREA) { // if node is 'Server' then the HasNotifier is implicit, so return true if (nodeName == "Server") { return true; } references = browse.Browse(nodeId); foreach (ReferenceDescription reference in references) { if ((reference.ReferenceTypeId == ReferenceTypes.HasNotifier) || (reference.ReferenceTypeId == ReferenceTypes.HasEventSource)) { return IsEventNotificationListAllowed(nodeId); } } } // For a node to be a source, it should be the target of the HasEventSource reference else // Check if this is a source. { IList<INode> parent = m_session.NodeCache.Find(nodeId, ReferenceTypes.HasEventSource, true, false); if (parent.Count != 0) return true; } } catch (Exception e) { Utils.Trace(e, "Unexpected error in IsValidNode"); } return false; }
/// <summary> /// Adds the targets of references to the control. /// </summary> private void AddReferences(NodeId referenceTypeId, BrowseDirection browseDirection) { // fetch the attributes for the reference type. INode referenceType = m_session.NodeCache.Find(referenceTypeId); if (referenceType == null) { return; } // browse for the references. Browser browser = new Browser(m_session); browser.BrowseDirection = browseDirection; browser.ReferenceTypeId = referenceTypeId; browser.IncludeSubtypes = true; browser.NodeClassMask = 0; browser.ContinueUntilDone = true; ReferenceDescriptionCollection references = browser.Browse(m_nodeId); // add results to list. foreach (ReferenceDescription reference in references) { NodeField field = new NodeField(); field.Name = referenceType.ToString(); field.Value = reference.ToString(); field.StatusCode = StatusCodes.Good; AddItem(field, "ReferenceType", -1); } }
/// <summary> /// Returns the list of attribute data of the event category specified /// </summary> /// <param name="dwEventCategory"></param> public List<EventAttribute> GetEventAttributes(int dwEventCategory) { List<EventAttribute> Attrs = new List<EventAttribute>(); try { Boolean BaseObjectTypeProcessed = false; Browser browseEventTypes = new Browser(m_session); browseEventTypes.BrowseDirection = BrowseDirection.Inverse; Browser browseVars = new Browser(m_session); browseVars.NodeClassMask = (int)NodeClass.Variable; browseVars.ReferenceTypeId = Opc.Ua.ReferenceTypes.HasProperty; ReferenceDescriptionCollection references = null; NodeId typeNodeId = FindEventCatNodeId(dwEventCategory); while (!BaseObjectTypeProcessed) { references = browseVars.Browse(typeNodeId); foreach (ReferenceDescription reference in references) { EventAttribute attribute = FindEventAttrInfo(reference.NodeId.ToString()); if (attribute != null) Attrs.Add(attribute); } if (typeNodeId.Equals(Opc.Ua.ObjectTypes.BaseObjectType)) { BaseObjectTypeProcessed = true; break; } if (typeNodeId.Equals(Opc.Ua.ObjectTypes.BaseEventType)) { BaseObjectTypeProcessed = true; Attrs.Add(FindEventAttrInfo("Areas")); } else { if (typeNodeId.Equals(Opc.Ua.ObjectTypes.ConditionType)) Attrs.Add(FindEventAttrInfo("AckComment")); references = browseEventTypes.Browse(typeNodeId); foreach (ReferenceDescription refDesc in references) { if (refDesc.ReferenceTypeId == ReferenceTypes.HasSubtype) { typeNodeId = (NodeId)refDesc.NodeId; //TODO: Can a type have only one parent? break; } } } } } catch (Exception e) { Utils.Trace(e, "Unexpected error in GetEventAttributes"); } return Attrs; }
/// <summary> /// Returns the data dictionary that constains the description. /// </summary> /// <param name="descriptionId">The description id.</param> /// <returns></returns> public DataDictionary FindDataDictionary(NodeId descriptionId) { // check if the dictionary has already been loaded. foreach (DataDictionary dictionary in m_dictionaries.Values) { if (dictionary.Contains(descriptionId)) { return dictionary; } } // find the dictionary for the description. Browser browser = new Browser(this); browser.BrowseDirection = BrowseDirection.Inverse; browser.ReferenceTypeId = ReferenceTypeIds.HasComponent; browser.IncludeSubtypes = false; browser.NodeClassMask = 0; ReferenceDescriptionCollection references = browser.Browse(descriptionId); if (references.Count == 0) { throw ServiceResultException.Create(StatusCodes.BadNodeIdInvalid, "Description does not refer to a valid data dictionary."); } // load the dictionary. NodeId dictionaryId = ExpandedNodeId.ToNodeId(references[0].NodeId, m_namespaceUris); DataDictionary dictionaryToLoad = new DataDictionary(this); dictionaryToLoad.Load(references[0]); m_dictionaries[dictionaryId] = dictionaryToLoad; return dictionaryToLoad; }
/// <summary> /// Returns the data description for the encoding. /// </summary> /// <param name="encodingId">The encoding Id.</param> /// <returns></returns> public ReferenceDescription FindDataDescription(NodeId encodingId) { Browser browser = new Browser(this); browser.BrowseDirection = BrowseDirection.Forward; browser.ReferenceTypeId = ReferenceTypeIds.HasDescription; browser.IncludeSubtypes = false; browser.NodeClassMask = 0; ReferenceDescriptionCollection references = browser.Browse(encodingId); if (references.Count == 0) { throw ServiceResultException.Create(StatusCodes.BadNodeIdInvalid, "Encoding does not refer to a valid data description."); } return references[0]; }
/// <summary> /// Returns the available encodings for a node /// </summary> /// <param name="variableId">The variable node.</param> /// <returns></returns> public ReferenceDescriptionCollection ReadAvailableEncodings(NodeId variableId) { VariableNode variable = NodeCache.Find(variableId) as VariableNode; if (variable == null) { throw ServiceResultException.Create(StatusCodes.BadNodeIdInvalid, "NodeId does not refer to a valid variable node."); } // no encodings available if there was a problem reading the data type for the node. if (NodeId.IsNull(variable.DataType)) { return new ReferenceDescriptionCollection(); } // no encodings for non-structures. if (!TypeTree.IsTypeOf(variable.DataType, DataTypes.Structure)) { return new ReferenceDescriptionCollection(); } // look for cached values. IList<INode> encodings = NodeCache.Find(variableId, ReferenceTypeIds.HasEncoding, false, true); if (encodings.Count > 0) { ReferenceDescriptionCollection references = new ReferenceDescriptionCollection(); foreach (INode encoding in encodings) { ReferenceDescription reference = new ReferenceDescription(); reference.ReferenceTypeId = ReferenceTypeIds.HasEncoding; reference.IsForward = true; reference.NodeId = encoding.NodeId; reference.NodeClass = encoding.NodeClass; reference.BrowseName = encoding.BrowseName; reference.DisplayName = encoding.DisplayName; reference.TypeDefinition = encoding.TypeDefinitionId; references.Add(reference); } return references; } Browser browser = new Browser(this); browser.BrowseDirection = BrowseDirection.Forward; browser.ReferenceTypeId = ReferenceTypeIds.HasEncoding; browser.IncludeSubtypes = false; browser.NodeClassMask = 0; return browser.Browse(variable.DataType); }
/// <summary> /// Gets the aggregate functions object id. /// </summary> /// <param name="session">The session.</param> /// <param name="objectId">The object id.</param> /// <returns>The node id.</returns> private List<HdaAggregate> GetAggregateFunctions(Session session, NodeId objectId) { Browser browser = new Browser(session); browser.BrowseDirection = BrowseDirection.Forward; browser.ReferenceTypeId = Opc.Ua.ReferenceTypeIds.HierarchicalReferences; browser.IncludeSubtypes = true; browser.NodeClassMask = (int)NodeClass.Object; browser.ResultMask = (uint)(BrowseResultMask.DisplayName | BrowseResultMask.BrowseName | BrowseResultMask.TypeDefinition); browser.ContinueUntilDone = true; ReferenceDescriptionCollection references = browser.Browse(objectId); List<HdaAggregate> aggregates = new List<HdaAggregate>(); for (int ii = 0; ii < references.Count; ii++) { ReferenceDescription reference = references[ii]; if (reference.TypeDefinition != Opc.Ua.ObjectTypeIds.AggregateFunctionType) { continue; } HdaAggregate aggregate = new HdaAggregate(); NodeId remoteId = (NodeId)reference.NodeId; aggregate.RemoteId = remoteId; aggregate.LocalId = ComUtils.GetHdaAggregateId(remoteId); aggregate.Name = reference.ToString(); aggregate.Description = null; // check for previously mapped ids. if (aggregate.LocalId == 0) { aggregate.LocalId = m_mapper.GetLocalIntegerIdMapping(Opc.Ua.BrowseNames.AggregateFunctions, remoteId); } aggregates.Add(aggregate); } return aggregates; }
/// <summary> /// Adds the properties to the control. /// </summary> private void AddProperties(ExpandedNodeId nodeId) { // get node. Node node = m_session.NodeCache.Find(nodeId) as Node; if (node == null) { return; } // get properties from supertype. ExpandedNodeId supertypeId = node.GetSuperType(m_session.TypeTree); if (supertypeId != null) { AddProperties(supertypeId); } // build list of properties to read. ReadValueIdCollection nodesToRead = new ReadValueIdCollection(); Browser browser = new Browser(m_session); browser.BrowseDirection = BrowseDirection.Forward; browser.ReferenceTypeId = ReferenceTypeIds.HasProperty; browser.IncludeSubtypes = true; browser.NodeClassMask = (int)NodeClass.Variable; browser.ContinueUntilDone = true; ReferenceDescriptionCollection references = browser.Browse(node.NodeId); // add propertoes to view. foreach (ReferenceDescription reference in references) { PropertyItem field = new PropertyItem(); field.Reference = reference; field.Property = m_session.NodeCache.Find(reference.NodeId) as VariableNode; AddItem(field, "Property", -1); } }
/// <summary> /// If this node is not abstract, add it as a category to the EventCategories list /// and process all nodes beneath it as categories. /// Also, add all of its atrributes to the EventAttributes list /// </summary> /// <param name="nodeId">The node being processed</param> /// <param name="CategoryType">The category type id this node will be added as </param> private void ProcessNodeAsCategory(NodeId nodeId, int CategoryType) { try { Node node = m_session.ReadNode(nodeId); EventCategory cat = new EventCategory(); DataValue value = new DataValue(); cat.CategoryID = m_catID++; cat.strNodeId = node.NodeId.ToString(); cat.BrowseName = node.BrowseName.ToString(); cat.EventDesc = node.DisplayName.Text; cat.EventType = CategoryType; m_EventCategories.Add(cat); Browser browse = new Browser(m_session); ReferenceDescriptionCollection references = null; references = browse.Browse(nodeId); foreach (ReferenceDescription reference in references) { if (reference.NodeClass == NodeClass.ObjectType) { ProcessNodeAsCategory((NodeId)reference.NodeId, CategoryType); } else if ((reference.NodeClass == NodeClass.Variable) && (reference.ReferenceTypeId == Opc.Ua.ReferenceTypes.HasProperty)) { ProcessNodeAsAttribute(nodeId, reference); } } } catch (Exception e) { Utils.Trace(e, "Unexpected error in ProcessNodesAsCategory"); } }
/// <summary> /// Initializing the configuration data. (allUsers + @"\Application Data\OPC Foundation\COM Interop\" + remoteServerDlg.PseudoClassID) /// </summary> private void InitConfigInfo(string configFileName) { try { Browser browser = new Browser(m_session); ReferenceDescriptionCollection references = browser.Browse(Opc.Ua.ObjectTypes.BaseEventType); if (references == null) { throw new Exception("No BaseEventType found in the type hierarchy"); } foreach (ReferenceDescription reference in references) { // check for base event types. if (reference.NodeClass == NodeClass.ObjectType) { int cattype = OpcRcw.Ae.Constants.SIMPLE_EVENT; if (reference.NodeId == Opc.Ua.ObjectTypes.ConditionType) { cattype = OpcRcw.Ae.Constants.CONDITION_EVENT; } else if (reference.NodeId == Opc.Ua.ObjectTypes.AuditEventType) { cattype = OpcRcw.Ae.Constants.TRACKING_EVENT; } ProcessNodeAsCategory((NodeId)reference.NodeId, cattype); } // check for properties. else if (reference.NodeClass == NodeClass.Variable) { if (reference.TypeDefinition == Opc.Ua.VariableTypeIds.PropertyType) { ProcessNodeAsAttribute(Opc.Ua.ObjectTypes.BaseEventType, reference); } } } // Add two special attribute for compatibility with AE COM EventAttribute attr1 = new EventAttribute(); attr1.AttributeID = Global.TheGlobal.StdAttrIds[1]; attr1.strNodeId = "Areas"; attr1.BrowseName = "AECOMAreas"; attr1.BrowseNameNSIndex = 0; attr1.AttrDesc = "Areas"; attr1.strDataTypeNodeId = DataTypes.GetDataTypeId(typeof(string[])).ToString(); attr1.strEventNodeId = ""; attr1.IsArray = true; attr1.ActualDataType = typeof(string[]); m_EventAttributes.Add(attr1); attr1 = new EventAttribute(); attr1.AttributeID = Global.TheGlobal.StdAttrIds[0]; attr1.strNodeId = "AckComment"; attr1.BrowseName = "AECOMAckComment"; attr1.BrowseNameNSIndex = 0; attr1.AttrDesc = "AckComment"; attr1.strDataTypeNodeId = DataTypes.GetDataTypeId(typeof(string)).ToString(); attr1.strEventNodeId = ""; attr1.IsArray = false; attr1.ActualDataType = typeof(string); m_EventAttributes.Add(attr1); m_EventAttributes.Sort(EventAttributeNodeIdCompare); m_EventCategories.Sort(EventCategoryBrowseNameCompare); m_configFile.Categories = m_EventCategories.ToArray(); m_configFile.Attributes = m_EventAttributes.ToArray(); m_configFile.LastEventCategoryID = m_catID; m_configFile.LastEventAttributeID = m_attrID; m_configFile.SavedNamespaceTable = m_session.NamespaceUris.ToArray(); } catch (Exception e) { Utils.Trace(e, "Unexpected error in InitConfigInfo"); } }
/// <summary> /// /// </summary> private void AddSessions() { Browser browser = new Browser(m_Session); browser.MaxReferencesReturned = 0; browser.BrowseDirection = BrowseDirection.Forward; browser.IncludeSubtypes = true; browser.NodeClassMask = (int)NodeClass.Object; browser.ContinueUntilDone = true; NodeId browseid = new NodeId(Objects.Server_ServerDiagnostics_SessionsDiagnosticsSummary); browser.ReferenceTypeId = null; ReferenceDescriptionCollection refs = browser.Browse(browseid); foreach(ReferenceDescription rf in refs) { if(m_Session.TypeTree.IsTypeOf(new ExpandedNodeId(rf.TypeDefinition), new ExpandedNodeId(ObjectTypes.SessionDiagnosticsObjectType))) { if(listView1.Items.IndexOfKey(rf.NodeId.ToString()) == -1) { ListViewItem lvi = listView1.Items.Add(rf.NodeId.ToString(), rf.DisplayName.Text.ToString(), -1); lvi.Tag = rf.NodeId; lvi.IndentCount = 0; string SessionID = "SessionDiagnostics.SessionId"; string ClientName = "SessionDiagnostics.ClientName"; string ClientConnectionTime = "SessionDiagnostics.ClientConnectionTime"; ListViewItem.ListViewSubItem SessionIDSubItem = lvi.SubItems.Add(""); SessionIDSubItem.Name = rf.NodeId.Identifier.ToString() + "." + SessionID; ListViewItem.ListViewSubItem ClientNameSubItem = lvi.SubItems.Add(""); ClientNameSubItem.Name = rf.NodeId.Identifier.ToString() + "." + ClientName; ListViewItem.ListViewSubItem ClientConnectionTimeSubItem = lvi.SubItems.Add(""); ClientConnectionTimeSubItem.Name = rf.NodeId.Identifier.ToString() + "." + ClientConnectionTime; MonitoredItem sessionItem = new MonitoredItem(m_Subscription.DefaultItem); sessionItem.StartNodeId = (NodeId)rf.NodeId; sessionItem.RelativePath = SessionID; sessionItem.NodeClass = NodeClass.Object; sessionItem.AttributeId = Attributes.Value; m_Subscription.AddItem(sessionItem); sessionItem.Notification += m_ItemNotification; INode node = m_Session.NodeCache.Find(rf.NodeId); TypedMonitoredItem SessionIDItem = new TypedMonitoredItem(m_Subscription.DefaultItem); SessionIDItem.StartNodeId = (NodeId)rf.NodeId; SessionIDItem.RelativePath = SessionID; SessionIDItem.NodeClass = NodeClass.Variable; SessionIDItem.AttributeId = Attributes.Value; m_Subscription.AddItem(SessionIDItem); SessionIDItem.Notification += m_ItemNotification; SessionIDSubItem.Tag = SessionIDItem; Utils.Trace("Adding: {0}, {1} as subitem in AddSessions()", SessionIDItem.StartNodeId.ToString(), SessionIDItem.RelativePath.ToString()); TypedMonitoredItem ClientNameItem = new TypedMonitoredItem(m_Subscription.DefaultItem); ClientNameItem.StartNodeId = (NodeId)rf.NodeId; ClientNameItem.RelativePath = ClientName; ClientNameItem.NodeClass = NodeClass.Variable; ClientNameItem.AttributeId = Attributes.Value; m_Subscription.AddItem(ClientNameItem); ClientNameItem.Notification += m_ItemNotification; ClientNameSubItem.Tag = ClientNameItem; Utils.Trace("Adding: {0}, {1} as subitem in AddSessions()", ClientNameItem.StartNodeId.ToString(), ClientNameItem.RelativePath.ToString()); DateTimeMonitoredItem ClientConnectionTimeItem = new DateTimeMonitoredItem(m_Subscription.DefaultItem); ClientConnectionTimeItem.StartNodeId = (NodeId)rf.NodeId; ClientConnectionTimeItem.RelativePath = ClientConnectionTime; ClientConnectionTimeItem.NodeClass = NodeClass.Variable; ClientConnectionTimeItem.AttributeId = Attributes.Value; m_Subscription.AddItem(ClientConnectionTimeItem); ClientConnectionTimeItem.Notification += m_ItemNotification; ClientConnectionTimeSubItem.Tag = ClientConnectionTimeItem; Utils.Trace("Adding: {0}, {1} as subitem in AddSessions()", ClientConnectionTimeItem.StartNodeId.ToString(), ClientConnectionTimeItem.RelativePath.ToString()); } else { Utils.Trace("Key already exists in listview. rf.BrowseName: {0},rf.NodeId: {1}, rf.TypeDefinition: {2}", rf.BrowseName.ToString(), rf.NodeId.ToString(), rf.TypeDefinition.ToString()); } } else { Utils.Trace("Unknown Object rf.BrowseName: {0},rf.NodeId: {1}, rf.TypeDefinition: {2}", rf.BrowseName.ToString(), rf.NodeId.ToString(), rf.TypeDefinition.ToString()); } } }
/// <summary> /// /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void subscriptionDiagnosticsToolStripMenuItem_Click(object sender, EventArgs e) { try { if (listView1.SelectedItems.Count > 0) { ListViewItem lvi = listView1.SelectedItems[0]; Browser browser = new Browser(m_Session); browser.MaxReferencesReturned = 0; browser.BrowseDirection = BrowseDirection.Forward; browser.IncludeSubtypes = true; browser.NodeClassMask = (int)NodeClass.Variable; browser.ContinueUntilDone = true; browser.ReferenceTypeId = null; NodeId sessionNodeId = new NodeId(lvi.Tag.ToString()); ReferenceDescriptionCollection refs = browser.Browse(sessionNodeId); foreach (ReferenceDescription rf in refs) { if (m_Session.TypeTree.IsTypeOf(new ExpandedNodeId(rf.TypeDefinition), new ExpandedNodeId(VariableTypes.SubscriptionDiagnosticsArrayType))) { MonitoredItem mi = new MonitoredItem(m_Subscription.DefaultItem); NodeId id = new NodeId(rf.NodeId.ToString()); INode node = m_Session.NodeCache.Find(id); mi.StartNodeId = id; mi.NodeClass = node.NodeClass; mi.AttributeId = Attributes.Value; mi.DisplayName = m_Session.NodeCache.GetDisplayText(node); mi.MonitoringMode = MonitoringMode.Reporting; m_Subscription.PublishingEnabled = true; m_Subscription.AddItem(mi); m_Subscription.ModifyItems(); m_Subscription.ApplyChanges(); MonitoredItemDlg dlg = new MonitoredItemDlg(); m_Forms.Add(dlg); dlg.Show(mi); break; } } } } catch (Exception exception) { GuiUtils.HandleException(this.Text, MethodBase.GetCurrentMethod(), exception); } }
/// <summary> /// Adds the properties to the control. /// </summary> private void AddProperties() { // build list of properties to read. ReadValueIdCollection nodesToRead = new ReadValueIdCollection(); Browser browser = new Browser(m_session); browser.BrowseDirection = BrowseDirection.Forward; browser.ReferenceTypeId = ReferenceTypeIds.HasProperty; browser.IncludeSubtypes = true; browser.NodeClassMask = (int)NodeClass.Variable; browser.ContinueUntilDone = true; ReferenceDescriptionCollection references = browser.Browse(m_nodeId); foreach (ReferenceDescription reference in references) { ReadValueId valueId = new ReadValueId(); valueId.NodeId = (NodeId)reference.NodeId; valueId.AttributeId = Attributes.Value; valueId.IndexRange = null; valueId.DataEncoding = null; nodesToRead.Add(valueId); } // check for empty list. if (nodesToRead.Count == 0) { return; } // read values. DataValueCollection values; DiagnosticInfoCollection diagnosticInfos; m_session.Read( null, 0, TimestampsToReturn.Neither, nodesToRead, out values, out diagnosticInfos); ClientBase.ValidateResponse(values, nodesToRead); ClientBase.ValidateDiagnosticInfos(diagnosticInfos, nodesToRead); // update control. for (int ii = 0; ii < nodesToRead.Count; ii++) { NodeField field = new NodeField(); field.ValueId = nodesToRead[ii]; field.Name = references[ii].ToString(); field.Value = values[ii].Value; field.StatusCode = values[ii].StatusCode; if (diagnosticInfos != null && diagnosticInfos.Count > ii) { field.DiagnosticInfo = diagnosticInfos[ii]; } AddItem(field, "Property", -1); } }