diff --git a/Libraries/Opc.Ua.Client/Events/EventField.cs b/Libraries/Opc.Ua.Client/Events/EventField.cs
new file mode 100644
index 0000000000..b00b4ac1b7
--- /dev/null
+++ b/Libraries/Opc.Ua.Client/Events/EventField.cs
@@ -0,0 +1,38 @@
+namespace Opc.Ua.Client.Events
+{
+ ///
+ /// Object representing an event field
+ ///
+ public class EventField
+ {
+ ///
+ /// Name of this event field
+ ///
+ public string Name { get; }
+
+ ///
+ /// Value of this event
+ ///
+ public Variant Value { get; }
+
+ ///
+ /// Object representing an event field
+ ///
+ /// Name of the field
+ /// Value of the field
+ public EventField(string name, Variant value)
+ {
+ Name = name;
+ Value = value;
+ }
+
+ ///
+ /// String representation: [Name]: [Value]
+ ///
+ ///
+ public override string ToString()
+ {
+ return $"{Name}: {Value}";
+ }
+ }
+}
diff --git a/Libraries/Opc.Ua.Client/Events/Extensions.cs b/Libraries/Opc.Ua.Client/Events/Extensions.cs
new file mode 100644
index 0000000000..c0136d38bf
--- /dev/null
+++ b/Libraries/Opc.Ua.Client/Events/Extensions.cs
@@ -0,0 +1,97 @@
+using System;
+using System.Linq;
+
+namespace Opc.Ua.Client.Events
+{
+ ///
+ ///
+ ///
+ public static class Extensions
+ {
+
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static ReferenceDescriptionCollection FetchReferences(this ISession session, NodeId nodeId, BrowseDirection browseDirection, NodeId referenceTypeId)
+ {
+ if (session is null)
+ {
+ throw new ArgumentNullException(nameof(session));
+ }
+ // browse for all references.
+ byte[] continuationPoint;
+ ReferenceDescriptionCollection descriptions;
+
+ session.Browse(
+ null,
+ null,
+ nodeId,
+ 0,
+ browseDirection,
+ referenceTypeId,
+ true,
+ 0,
+ out continuationPoint,
+ out descriptions);
+
+ // process any continuation point.
+ while (continuationPoint != null)
+ {
+ byte[] revisedContinuationPoint;
+ ReferenceDescriptionCollection additionalDescriptions;
+
+ session.BrowseNext(
+ null,
+ false,
+ continuationPoint,
+ out revisedContinuationPoint,
+ out additionalDescriptions);
+
+ continuationPoint = revisedContinuationPoint;
+
+ descriptions.AddRange(additionalDescriptions);
+ }
+
+ return descriptions;
+ }
+
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static DataValueCollection Read(this ISession session, ReadValueIdCollection rvic)
+ {
+ session.Read(null, 0, TimestampsToReturn.Neither, rvic, out DataValueCollection dt, out DiagnosticInfoCollection dg);
+ return dt;
+ }
+
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static DataValue Read(this ISession session, ReadValueId rvi)
+ {
+ return session.Read(new ReadValueIdCollection { rvi }).First();
+ }
+
+
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static NodeId ToNodeId(this ReferenceDescription id)
+ {
+ return ExpandedNodeId.ToNodeId(id.NodeId, new NamespaceTable());
+ }
+ }
+}
diff --git a/Libraries/Opc.Ua.Client/Events/IEvent.cs b/Libraries/Opc.Ua.Client/Events/IEvent.cs
new file mode 100644
index 0000000000..38532ad8c1
--- /dev/null
+++ b/Libraries/Opc.Ua.Client/Events/IEvent.cs
@@ -0,0 +1,31 @@
+using System.Collections.Generic;
+using Opc.Ua.Client.Methods;
+
+namespace Opc.Ua.Client.Events
+{
+ ///
+ /// Interface of an event
+ ///
+ public interface IEvent
+ {
+ ///
+ /// Event fields
+ ///
+ IReadOnlyList Fields { get; }
+
+ ///
+ /// Acknowledge
+ ///
+ MethodCallReturnValue Acknowledge(LocalizedText comment);
+
+ ///
+ /// Confirm
+ ///
+ MethodCallReturnValue Confirm(LocalizedText comment);
+
+ ///
+ /// Add comment to this event
+ ///
+ MethodCallReturnValue AddComment(LocalizedText comment);
+ }
+}
diff --git a/Libraries/Opc.Ua.Client/Events/ISessionContainer.cs b/Libraries/Opc.Ua.Client/Events/ISessionContainer.cs
new file mode 100644
index 0000000000..65fb9e704a
--- /dev/null
+++ b/Libraries/Opc.Ua.Client/Events/ISessionContainer.cs
@@ -0,0 +1,13 @@
+namespace Opc.Ua.Client.Events
+{
+ ///
+ /// Interface for an object containing the session
+ ///
+ public interface ISessionContainer
+ {
+ ///
+ /// The contained session object
+ ///
+ ISession Session { get; set; }
+ }
+}
diff --git a/Libraries/Opc.Ua.Client/Events/OpcEvent.cs b/Libraries/Opc.Ua.Client/Events/OpcEvent.cs
new file mode 100644
index 0000000000..8ef0061f4c
--- /dev/null
+++ b/Libraries/Opc.Ua.Client/Events/OpcEvent.cs
@@ -0,0 +1,67 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Opc.Ua.Client.Methods;
+
+namespace Opc.Ua.Client.Events
+{
+ ///
+ /// Object for an event
+ ///
+ public class OpcEvent : IEvent
+ {
+ ///
+ /// Event fields
+ ///
+ public IReadOnlyList Fields { get; }
+
+ private readonly NodeId _objectNodeId;
+ private readonly byte[] _eventId;
+ private readonly IEventMethodCollection _eventMethods;
+
+ ///
+ /// Constructor
+ ///
+ public OpcEvent(IEventMethodCollection eventMethods, IEnumerable fields)
+ {
+ Fields = fields.ToList();
+ _eventMethods = eventMethods;
+ _objectNodeId = GetEventField("ConditionNodeId", x => x.Name.Equals("ConditionId", StringComparison.Ordinal));
+ _eventId = GetEventField("EventId", x => x.Name.Equals("/EventId", StringComparison.Ordinal));
+ }
+
+ ///
+ /// Acknowledge this event
+ ///
+ public MethodCallReturnValue Acknowledge(LocalizedText comment)
+ {
+ return _eventMethods.Acknowledge.CallMethod(_objectNodeId, _eventId, comment);
+ }
+
+ ///
+ /// Confirm this event
+ ///
+ public MethodCallReturnValue Confirm(LocalizedText comment)
+ {
+ return _eventMethods.Confirm.CallMethod(_objectNodeId, _eventId, comment);
+ }
+
+ ///
+ /// Add comment to this event
+ ///
+ public MethodCallReturnValue AddComment(LocalizedText comment)
+ {
+ return _eventMethods.AddComment.CallMethod(_objectNodeId, _eventId, comment);
+ }
+
+ private T GetEventField(string eventFieldName, Func searchCriteria)
+ {
+ var relevantField = Fields.FirstOrDefault(searchCriteria);
+ if (relevantField is null)
+ {
+ throw new OpcUaEventFieldNotFoundException(eventFieldName);
+ }
+ return (T)relevantField.Value.Value;
+ }
+ }
+}
diff --git a/Libraries/Opc.Ua.Client/Events/OpcUaEventFieldNotFoundException.cs b/Libraries/Opc.Ua.Client/Events/OpcUaEventFieldNotFoundException.cs
new file mode 100644
index 0000000000..3c0b583b41
--- /dev/null
+++ b/Libraries/Opc.Ua.Client/Events/OpcUaEventFieldNotFoundException.cs
@@ -0,0 +1,65 @@
+using System;
+
+namespace Opc.Ua.Client.Events
+{
+ ///
+ /// Exception when event field not found
+ ///
+ public class OpcUaEventFieldNotFoundException : Exception
+ {
+ private const string DefaultMessage = "Event field with given name not found!";
+
+ ///
+ /// Name of the event field
+ ///
+ public string EventFieldName { get; }
+
+ ///
+ /// Exception when event field not found
+ ///
+ public OpcUaEventFieldNotFoundException(string eventFieldName)
+ : this(eventFieldName, "")
+ {
+ EventFieldName = eventFieldName;
+ }
+
+ ///
+ /// Exception when event field not found
+ ///
+ public OpcUaEventFieldNotFoundException(string eventFieldName, string userMessage)
+ : this(eventFieldName, userMessage, null)
+ {
+
+ }
+
+ ///
+ /// Exception when event field not found
+ ///
+ public OpcUaEventFieldNotFoundException() : this("")
+ {
+
+ }
+
+ ///
+ /// Exception when event field not found
+ ///
+ ///
+ ///
+ public OpcUaEventFieldNotFoundException(string message, Exception innerException) : this("", message, innerException)
+ {
+
+ }
+
+ ///
+ /// Exception when event field not found
+ ///
+ /// Field that was not found
+ /// userdefined message for the exception
+ /// Inner Exception
+ public OpcUaEventFieldNotFoundException(string eventFieldName, string userMessage, Exception innerException)
+ : base($"{DefaultMessage}{eventFieldName}{userMessage}", innerException)
+ {
+ EventFieldName = eventFieldName;
+ }
+ }
+}
diff --git a/Libraries/Opc.Ua.Client/Methods/EventMethod.cs b/Libraries/Opc.Ua.Client/Methods/EventMethod.cs
new file mode 100644
index 0000000000..031db64c85
--- /dev/null
+++ b/Libraries/Opc.Ua.Client/Methods/EventMethod.cs
@@ -0,0 +1,22 @@
+using System.Collections.Generic;
+
+namespace Opc.Ua.Client.Methods
+{
+ ///
+ /// A standard event method
+ ///
+ internal class EventMethod : MethodBase, IEventMethod
+ {
+ internal EventMethod(ISession session, NodeId methodNodeId) : base(session, methodNodeId)
+ {
+ }
+
+ ///
+ /// Call this method
+ ///
+ public MethodCallReturnValue CallMethod(NodeId objectNodeId, byte[] eventId, LocalizedText comment)
+ {
+ return Call(objectNodeId, new List { eventId, comment });
+ }
+ }
+}
diff --git a/Libraries/Opc.Ua.Client/Methods/EventMethodCollection.cs b/Libraries/Opc.Ua.Client/Methods/EventMethodCollection.cs
new file mode 100644
index 0000000000..3c322d6bc3
--- /dev/null
+++ b/Libraries/Opc.Ua.Client/Methods/EventMethodCollection.cs
@@ -0,0 +1,30 @@
+namespace Opc.Ua.Client.Methods
+{
+ ///
+ /// Method collection for standard events
+ ///
+ public class EventMethodCollection : IEventMethodCollection
+ {
+ ///
+ /// Acknowledge
+ ///
+ public IEventMethod Acknowledge { get; }
+
+ ///
+ /// Confirm
+ ///
+ public IEventMethod Confirm { get; }
+
+ ///
+ /// Add comment
+ ///
+ public IEventMethod AddComment { get; }
+
+ internal EventMethodCollection(ISession session)
+ {
+ Acknowledge = new EventMethod(session, MethodIds.AcknowledgeableConditionType_Acknowledge);
+ Confirm = new EventMethod(session, MethodIds.AcknowledgeableConditionType_Confirm);
+ AddComment = new EventMethod(session, MethodIds.ConditionType_AddComment);
+ }
+ }
+}
diff --git a/Libraries/Opc.Ua.Client/Methods/IEventMethod.cs b/Libraries/Opc.Ua.Client/Methods/IEventMethod.cs
new file mode 100644
index 0000000000..133edc244e
--- /dev/null
+++ b/Libraries/Opc.Ua.Client/Methods/IEventMethod.cs
@@ -0,0 +1,17 @@
+namespace Opc.Ua.Client.Methods
+{
+ ///
+ /// A standard event method
+ ///
+ public interface IEventMethod
+ {
+ ///
+ /// Call this method and Return a MethodCallReturnValue
+ ///
+ /// the Object NodeId
+ /// the EventId
+ /// Comment to set for the event
+ /// MethodCallReturnValue
+ MethodCallReturnValue CallMethod(NodeId objectNodeId, byte[] eventId, LocalizedText comment);
+ }
+}
diff --git a/Libraries/Opc.Ua.Client/Methods/IEventMethodCollection.cs b/Libraries/Opc.Ua.Client/Methods/IEventMethodCollection.cs
new file mode 100644
index 0000000000..265d51dafd
--- /dev/null
+++ b/Libraries/Opc.Ua.Client/Methods/IEventMethodCollection.cs
@@ -0,0 +1,23 @@
+namespace Opc.Ua.Client.Methods
+{
+ ///
+ /// Method collection for standard events
+ ///
+ public interface IEventMethodCollection
+ {
+ ///
+ /// Acknowledge
+ ///
+ IEventMethod Acknowledge { get; }
+
+ ///
+ /// Confirm
+ ///
+ IEventMethod Confirm { get; }
+
+ ///
+ /// Add comment
+ ///
+ IEventMethod AddComment { get; }
+ }
+}
diff --git a/Libraries/Opc.Ua.Client/Methods/MethodBase.cs b/Libraries/Opc.Ua.Client/Methods/MethodBase.cs
new file mode 100644
index 0000000000..032be183a2
--- /dev/null
+++ b/Libraries/Opc.Ua.Client/Methods/MethodBase.cs
@@ -0,0 +1,136 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Opc.Ua.Client.Events;
+
+namespace Opc.Ua.Client.Methods
+{
+ ///
+ /// Base object for method object
+ ///
+ internal abstract class MethodBase
+ {
+ private readonly ISession _session;
+ private NodeId _inputArgumentsNodeId;
+
+ ///
+ /// Node id of the input arguments, null if it does not exist
+ ///
+ protected NodeId InputArgumentsNodeId
+ {
+ get
+ {
+ if (_inputArgumentsNodeId == null)
+ {
+ LoadArguments();
+ }
+ return _inputArgumentsNodeId;
+ }
+ }
+
+ private NodeId _outputArgumentsNodeId;
+
+ ///
+ /// Node id of the output arguments, null if it does not exist
+ ///
+ protected NodeId OutputArgumentsNodeId
+ {
+ get
+ {
+ if (_outputArgumentsNodeId == null)
+ {
+ LoadArguments();
+ }
+ return _outputArgumentsNodeId;
+ }
+ }
+
+ ///
+ /// NodeId of the method
+ ///
+ public NodeId MethodNodeId { get; }
+
+ ///
+ /// Constructor
+ ///
+ protected MethodBase(ISession session, NodeId methodNodeId)
+ {
+ _session = session;
+ MethodNodeId = methodNodeId;
+ }
+
+ private void LoadArguments()
+ {
+ var references = _session.FetchReferences(MethodNodeId, BrowseDirection.Forward, ReferenceTypeIds.HasProperty);
+ foreach (var reference in references)
+ {
+ if (reference.BrowseName.Name.Equals("InputArguments", StringComparison.Ordinal))
+ {
+ _inputArgumentsNodeId = reference.ToNodeId();
+ }
+ else if (reference.BrowseName.Name.Equals("OutputArguments", StringComparison.Ordinal))
+ {
+ _outputArgumentsNodeId = reference.ToNodeId();
+ }
+ }
+ }
+
+ ///
+ /// Internal function call
+ ///
+ /// object NodeId
+ /// the list of parameter. if there are none, an empty list
+ protected MethodCallReturnValue Call(NodeId objectNodeId, IEnumerable parameters)
+ {
+ var callMethodRequestCollection = new CallMethodRequestCollection
+ {
+ new CallMethodRequest()
+ {
+ ObjectId = objectNodeId,
+ MethodId = MethodNodeId,
+ InputArguments = new VariantCollection(parameters)
+ }
+ };
+ CallMethodResultCollection results;
+ DiagnosticInfoCollection diagnosticInfos;
+
+ _session.Call(GetHeader(), callMethodRequestCollection, out results, out diagnosticInfos);
+
+ VariantCollection outputValues = results[0].OutputArguments;
+ List arguments = null;
+ if (OutputArgumentsNodeId != null)
+ {
+ var extObjs = (ExtensionObject[])_session.ReadValue(OutputArgumentsNodeId).Value;
+ arguments = extObjs.Select(x => (Argument)x.Body).ToList();
+ }
+
+ var convertedOutputArgs = GetOutputParameters(outputValues, arguments);
+
+ return new MethodCallReturnValue(results[0].StatusCode, convertedOutputArgs.ToList(), results[0].InputArgumentResults.ToList());
+
+ }
+
+ private RequestHeader GetHeader()
+ {
+ return new RequestHeader();
+ }
+
+ private List GetOutputParameters(VariantCollection values, IEnumerable arguments)
+ {
+ var convertedOutputArgs = new List();
+ for (int i = 0; i < values.Count; i++)
+ {
+ convertedOutputArgs.Add(GetOutputParameter(values[i], arguments.ElementAt(i)));
+ }
+ return convertedOutputArgs;
+ }
+
+ ///
+ /// Get output parameters
+ ///
+ protected virtual OutputArgument GetOutputParameter(Variant value, Argument argument)
+ {
+ return new OutputArgument() { Name = argument.Name, Value = value.Value };
+ }
+ }
+}
diff --git a/Libraries/Opc.Ua.Client/Methods/MethodCallReturnValue.cs b/Libraries/Opc.Ua.Client/Methods/MethodCallReturnValue.cs
new file mode 100644
index 0000000000..5144545573
--- /dev/null
+++ b/Libraries/Opc.Ua.Client/Methods/MethodCallReturnValue.cs
@@ -0,0 +1,33 @@
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+
+namespace Opc.Ua.Client.Methods
+{
+ ///
+ /// Return values of a method call
+ ///
+ public class MethodCallReturnValue
+ {
+ ///
+ /// Result of the method call
+ ///
+ public StatusCode Result { get; set; }
+
+ ///
+ /// Return values from the method call
+ ///
+ public ReadOnlyCollection ReturnValue { get; set; }
+
+ ///
+ /// Results of the parameters
+ ///
+ public ReadOnlyCollection ParameterResult { get; set; }
+
+ internal MethodCallReturnValue(StatusCode s, List returnValue, List parameterResult)
+ {
+ Result = s;
+ ReturnValue = new ReadOnlyCollection(returnValue);
+ ParameterResult = new ReadOnlyCollection(parameterResult);
+ }
+ }
+}
diff --git a/Libraries/Opc.Ua.Client/Methods/OutputArgument.cs b/Libraries/Opc.Ua.Client/Methods/OutputArgument.cs
new file mode 100644
index 0000000000..857ee13f96
--- /dev/null
+++ b/Libraries/Opc.Ua.Client/Methods/OutputArgument.cs
@@ -0,0 +1,24 @@
+namespace Opc.Ua.Client.Methods
+{
+ ///
+ /// An output argument of a method
+ ///
+ public class OutputArgument
+ {
+ ///
+ /// Name of this argument
+ ///
+ public string Name { get; set; }
+
+ ///
+ /// Value of this argument
+ ///
+ public object Value { get; set; }
+
+ ///
+ /// Method Name
+ ///
+ /// The Method Name
+ public override string ToString() => Name;
+ }
+}
diff --git a/Libraries/Opc.Ua.Client/MonitoredItem.cs b/Libraries/Opc.Ua.Client/MonitoredItem.cs
index fb02141ba1..7b065ac21f 100644
--- a/Libraries/Opc.Ua.Client/MonitoredItem.cs
+++ b/Libraries/Opc.Ua.Client/MonitoredItem.cs
@@ -30,6 +30,8 @@
using System;
using System.Collections.Generic;
using System.Runtime.Serialization;
+using Opc.Ua.Client.Events;
+using Opc.Ua.Client.Methods;
namespace Opc.Ua.Client
{
@@ -175,7 +177,120 @@ private void Initialize()
// assign a unique handle.
m_clientHandle = Utils.IncrementIdentifier(ref s_globalClientHandle);
+ AddEventHandler();
}
+
+ private bool AddedEventHandlers = false;
+
+ ///
+ /// Add Event Handler to MonitoredItem -> Notification
+ ///
+ public void AddEventHandler()
+ {
+ if (!AddedEventHandlers)
+ {
+ m_Notification += MonitoredItem_Notification;
+ AddedEventHandlers = true;
+ EventNotification += Event_Notification;
+ }
+ }
+
+ private void Event_Notification(EventFilter eventFilter, EventFieldList eventFieldList)
+ {
+ var acknowledgeableEvent = GetAcknowledgeableEvent(eventFilter, eventFieldList);
+
+ foreach (var field in acknowledgeableEvent.Fields)
+ {
+ Console.WriteLine($"{field.Name}:{field.Value}");
+ }
+ try
+ {
+ acknowledgeableEvent.AddComment(new LocalizedText("Commented!"));
+ Console.WriteLine($"Commented!");
+ }
+ catch (Exception e)
+ {
+ Console.WriteLine($"couldnt comment! {e}");
+ }
+ try
+ {
+ acknowledgeableEvent.Confirm(new LocalizedText("Confirmed!"));
+ Console.WriteLine($"Confirmed!");
+ }
+ catch (Exception e)
+ {
+ Console.WriteLine($"couldnt Confirm! {e}");
+ }
+ try
+ {
+ acknowledgeableEvent.Acknowledge(new LocalizedText("Acknowledged!"));
+ Console.WriteLine($"Acknowledged!");
+ }
+ catch (Exception e)
+ {
+ Console.WriteLine($"couldnt Acknowledge! {e}");
+ }
+ }
+
+ private void MonitoredItem_Notification(MonitoredItem monitoredItem, MonitoredItemNotificationEventArgs e)
+ {
+ var dataChangeNotification = e.NotificationValue as MonitoredItemNotification;
+ if (dataChangeNotification != null)
+ {
+ DataChangeNotification?.Invoke(dataChangeNotification);
+ return;
+ }
+
+ var eventMonitoredItemNotification = e.NotificationValue as EventFieldList;
+ if (eventMonitoredItemNotification != null)
+ {
+ EventNotification?.Invoke((EventFilter)monitoredItem.Filter, eventMonitoredItemNotification);
+ }
+ }
+
+ ///
+ /// Get an Acknowledgeable event
+ ///
+ ///
+ ///
+ ///
+ public IEvent GetAcknowledgeableEvent(EventFilter eventFilter, EventFieldList eventFieldList)
+ {
+ //ArgumentNullException.ThrowIfNull(eventFilter, nameof(eventFilter));
+ //ArgumentNullException.ThrowIfNull(eventFieldList, nameof(eventFieldList));
+ if (eventFilter == null)
+ {
+ throw new ArgumentNullException(nameof(eventFilter));
+ }
+ if (eventFieldList == null)
+ {
+ throw new ArgumentNullException(nameof(eventFieldList));
+ }
+ return new OpcEvent(new EventMethodCollection(this.Subscription.Session), GetWrappedEventFields(eventFilter, eventFieldList));
+ }
+
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ private List GetWrappedEventFields(EventFilter eventFilter, EventFieldList eventFieldList)
+ {
+ var eventFields = eventFieldList.EventFields;
+ var wrappedEventFields = new List();
+ for (int i = 0; i < eventFields.Count; i++)
+ {
+ var eventName = eventFilter.SelectClauses[i].ToString();
+ if (eventFilter.SelectClauses[i].AttributeId == Attributes.NodeId)
+ {
+ eventName = "ConditionId";
+ }
+ wrappedEventFields.Add(new EventField(eventName, eventFields[i]));
+ }
+ return wrappedEventFields;
+ }
+
#endregion
#region Persistent Properties
@@ -593,6 +708,15 @@ public event MonitoredItemNotificationEventHandler Notification
}
}
+ ///
+ /// DataChangeNotification for the Monitored Item
+ ///
+ public event MonitoredItemNotificationHandler DataChangeNotification;
+ ///
+ /// Event Notification for the Monitored Item
+ ///
+ public event EventMonitoredItemNotificationNotificationHandler EventNotification;
+
///
/// Reset the notification event handler.
///
@@ -1155,6 +1279,16 @@ internal MonitoredItemNotificationEventArgs(IEncodeable notificationValue)
/// The delegate used to receive monitored item value notifications.
///
public delegate void MonitoredItemNotificationEventHandler(MonitoredItem monitoredItem, MonitoredItemNotificationEventArgs e);
+
+ ///
+ /// Handler for data change notification
+ ///
+ public delegate void MonitoredItemNotificationHandler(MonitoredItemNotification notification);
+
+ ///
+ /// Handler for event change notification
+ ///
+ public delegate void EventMonitoredItemNotificationNotificationHandler(EventFilter eventFilter, EventFieldList eventFieldList);
#endregion
///