QuickOPC User's Guide and Reference
ItemChanged Event (IEasyDAClient)
Example 



OpcLabs.EasyOpcClassicCore Assembly > OpcLabs.EasyOpc.DataAccess Namespace > IEasyDAClient Interface : ItemChanged Event
Raised for every significant change in an OPC item subscribed to by the SubscribeItem method.
Syntax
'Declaration
 
Event ItemChanged As EasyDAItemChangedEventHandler
'Usage
 
Dim instance As IEasyDAClient
Dim handler As EasyDAItemChangedEventHandler
 
AddHandler instance.ItemChanged, handler
event EasyDAItemChangedEventHandler ItemChanged
event EasyDAItemChangedEventHandler^ ItemChanged
Event Data

The event handler receives an argument of type EasyDAItemChangedEventArgs containing data related to this event. The following EasyDAItemChangedEventArgs properties provide information specific to this event.

PropertyDescription
Holds arguments that were used to subscribe to an item in an OPC-DA server.  
Diagnostics information (such as warnings) assembled during the operation. (Inherited from OpcLabs.BaseLib.OperationModel.OperationEventArgs)
Count of diagnostic information elements assembled during the operation. (Inherited from OpcLabs.BaseLib.OperationModel.OperationEventArgs)
Textual summary of diagnostics information, one message per line. (Inherited from OpcLabs.BaseLib.OperationModel.OperationEventArgs)
Gets or sets the error ID of the error. (Inherited from OpcLabs.BaseLib.OperationModel.OperationEventArgs)
Gets or sets a message that describes the current exception. (Inherited from OpcLabs.BaseLib.OperationModel.OperationEventArgs)
The first line of the error message. (Inherited from OpcLabs.BaseLib.OperationModel.OperationEventArgs)
Gets the current exception. Contains null reference when no exception. (Inherited from OpcLabs.BaseLib.OperationModel.OperationEventArgs)
A normalized OpcLabs.BaseLib.OperationModel.OperationEventArgs.Diagnostics collection. (Inherited from OpcLabs.BaseLib.OperationModel.OperationEventArgs)
A normalized OpcLabs.BaseLib.OperationModel.OperationEventArgs.Exception object, or null if there was no error. (Inherited from OpcLabs.BaseLib.OperationModel.OperationEventArgs)
Status information corresponding to the contents of the event arguments.  
Gets indication whether the operation has succeeded. (Inherited from OpcLabs.BaseLib.OperationModel.OperationEventArgs)
Gets the current (new) OpcLabs.EasyOpc.DataAccess.DAVtq (value, timestamp and quality) of the OPC item. Null reference when System.Exception is not null.  
Example

.NET

.NET

.NET

// This example shows how subscribe to changes of multiple items and display each change, identifying the different
// subscriptions by an integer.

using System;
using System.Threading;
using OpcLabs.EasyOpc.DataAccess;
using OpcLabs.EasyOpc.DataAccess.OperationModel;

namespace DocExamples.DataAccess._EasyDAClient
{
    partial class SubscribeMultipleItems
    {
        public static void StateAsInteger()
        {
            // Instantiate the client object.
            using (var client = new EasyDAClient())
            {
                // Hook events
                client.ItemChanged += client_StateAsInteger_ItemChanged;

                Console.WriteLine("Subscribing...");
                int[] handleArray = client.SubscribeMultipleItems(new[]
                {
                    new DAItemGroupArguments("", "OPCLabs.KitServer.2", "Simulation.Random", 1000,
                        state: 1), // An integer we have chosen to identify the subscription
                    new DAItemGroupArguments("", "OPCLabs.KitServer.2", "Trends.Ramp (1 min)", 1000,
                        state: 2), // An integer we have chosen to identify the subscription
                    new DAItemGroupArguments("", "OPCLabs.KitServer.2", "Trends.Sine (1 min)", 1000,
                        state: 3), // An integer we have chosen to identify the subscription
                    new DAItemGroupArguments("", "OPCLabs.KitServer.2", "Simulation.Register_I4", 1000,
                        state: 4) // An integer we have chosen to identify the subscription
                });

                for (int i = 0; i < handleArray.Length; i++)
                    Console.WriteLine($"handleArray[{i}]: {handleArray[i]}");

                Console.WriteLine("Processing item changed events for 10 seconds...");
                Thread.Sleep(10 * 1000);

                Console.WriteLine("Unsubscribing...");
            }

            Console.WriteLine("Waiting for 5 seconds...");
            Thread.Sleep(5 * 1000);

            Console.WriteLine("Finished.");
        }

        // Item changed event handler
        static void client_StateAsInteger_ItemChanged(object sender, EasyDAItemChangedEventArgs eventArgs)
        {
            // Obtain the integer state we have passed in.
            var stateAsInteger = (int)eventArgs.Arguments.State;

            // Display the data
            if (eventArgs.Succeeded)
                Console.WriteLine($"{stateAsInteger}: {eventArgs.Vtq}");
            else
                Console.WriteLine($"{stateAsInteger} *** Failure: {eventArgs.ErrorMessageBrief}");
        }
    }
}
# This example shows how subscribe to changes of multiple items and display each change, identifying the different
# subscriptions by an integer.

# The QuickOPC package is needed. Install it using "pip install opclabs_quickopc".
import opclabs_quickopc
import time

# Import .NET namespaces.
from OpcLabs.EasyOpc.DataAccess import *
from OpcLabs.EasyOpc.DataAccess.OperationModel import *


# Item changed event handler.
def itemChanged(sender, eventArgs):
    # Obtain the integer state we have passed in.
    stateAsInteger = int(eventArgs.Arguments.State)
    if eventArgs.Succeeded:
        print(stateAsInteger, ': ', eventArgs.Vtq, sep='')
    else:
        print(stateAsInteger, ' *** Failure: ', eventArgs.ErrorMessageBrief, sep='')


# Instantiate the client object.
client = EasyDAClient()
# Hook events.
client.ItemChanged += itemChanged

print('Subscribing item changes...')
handleArray = IEasyDAClientExtension.SubscribeMultipleItems(client, [
    DAItemGroupArguments('', 'OPCLabs.KitServer.2', 'Simulation.Random', 1000,
                         1),    # an integer we have chosen to identify the subscription
    DAItemGroupArguments('', 'OPCLabs.KitServer.2', 'Trends.Ramp (1 min)', 1000,
                         2),    # an integer we have chosen to identify the subscription
    DAItemGroupArguments('', 'OPCLabs.KitServer.2', 'Trends.Sine (1 min)', 1000,
                         3),    # an integer we have chosen to identify the subscription
    DAItemGroupArguments('', 'OPCLabs.KitServer.2', 'Simulation.Register_I4', 1000,
                         4),    # an integer we have chosen to identify the subscription
    ])

for i in range(len(handleArray)):
    print('handleArray[', i, ']: ', handleArray[i], sep='')

print('Processing item change notifications for 1 minute...')
time.sleep(60)

print('Unsubscribing all items...')
client.UnsubscribeAllItems()

client.ItemChanged -= itemChanged

print('Finished.')
// This example shows how subscribe to changes of multiple items and display each change, identifying the different
// subscriptions by an object.

using System;
using System.Threading;
using OpcLabs.EasyOpc.DataAccess;
using OpcLabs.EasyOpc.DataAccess.OperationModel;

namespace DocExamples.DataAccess._EasyDAClient
{
    partial class SubscribeMultipleItems
    {
        class CustomObject
        {
            public CustomObject(string name)
            {
                Name = name;
            }

            public string Name { get; }
        }


        public static void StateAsObject()
        {
            // Instantiate the client object.
            using (var client = new EasyDAClient())
            {
                // Hook events
                client.ItemChanged += client_StateAsObject_ItemChanged;

                Console.WriteLine("Subscribing...");
                int[] handleArray = client.SubscribeMultipleItems(new[]
                {
                    new DAItemGroupArguments("", "OPCLabs.KitServer.2", "Simulation.Random", 1000,
                        new CustomObject("First")), // A custom object that corresponds to the subscription
                    new DAItemGroupArguments("", "OPCLabs.KitServer.2", "Trends.Ramp (1 min)", 1000,
                        new CustomObject("Second")), // A custom object that corresponds to the subscription
                    new DAItemGroupArguments("", "OPCLabs.KitServer.2", "Trends.Sine (1 min)", 1000,
                        new CustomObject("Third")), // A custom object that corresponds to the subscription
                    new DAItemGroupArguments("", "OPCLabs.KitServer.2", "Simulation.Register_I4", 1000,
                        new CustomObject("Fourth")) // A custom object that corresponds to the subscription
                });

                for (int i = 0; i < handleArray.Length; i++)
                    Console.WriteLine($"handleArray[{i}]: {handleArray[i]}");

                Console.WriteLine("Processing item changed events for 10 seconds...");
                Thread.Sleep(10 * 1000);

                Console.WriteLine("Unsubscribing...");
            }

            Console.WriteLine("Waiting for 5 seconds...");
            Thread.Sleep(5 * 1000);

            Console.WriteLine("Finished.");
        }

        // Item changed event handler
        static void client_StateAsObject_ItemChanged(object sender, EasyDAItemChangedEventArgs eventArgs)
        {
            // Obtain the custom object we have passed in.
            var stateAsObject = (CustomObject)eventArgs.Arguments.State;

            // Display the data
            if (eventArgs.Succeeded)
                Console.WriteLine($"{stateAsObject.Name}: {eventArgs.Vtq}");
            else
                Console.WriteLine($"{stateAsObject.Name} *** Failure: {eventArgs.ErrorMessageBrief}");
        }
    }
}
# This example shows how subscribe to changes of multiple items and display each change, identifying the different
# subscriptions by an object.

# The QuickOPC package is needed. Install it using "pip install opclabs_quickopc".
import opclabs_quickopc
import time

# Import .NET namespaces.
from OpcLabs.EasyOpc.DataAccess import *
from OpcLabs.EasyOpc.DataAccess.OperationModel import *


class CustomObject(object):
    def __init__(self, name):
        self.name = name


# Item changed event handler.
def itemChanged(sender, eventArgs):
    # Obtain the custom object we have passed in.
    stateAsObject = eventArgs.Arguments.State
    if eventArgs.Succeeded:
        print(stateAsObject.name, ': ', eventArgs.Vtq, sep='')
    else:
        print(stateAsObject.name, ' *** Failure: ', eventArgs.ErrorMessageBrief, sep='')


# Instantiate the client object.
client = EasyDAClient()
# Hook events.
client.ItemChanged += itemChanged

print('Subscribing item changes...')
handleArray = IEasyDAClientExtension.SubscribeMultipleItems(client, [
    DAItemGroupArguments('', 'OPCLabs.KitServer.2', 'Simulation.Random', 1000,
                         CustomObject('First')),    # a custom object that corresponds to the subscription
    DAItemGroupArguments('', 'OPCLabs.KitServer.2', 'Trends.Ramp (1 min)', 1000,
                         CustomObject('Second')),   # a custom object that corresponds to the subscription
    DAItemGroupArguments('', 'OPCLabs.KitServer.2', 'Trends.Sine (1 min)', 1000,
                         CustomObject('Third')),    # a custom object that corresponds to the subscription
    DAItemGroupArguments('', 'OPCLabs.KitServer.2', 'Simulation.Register_I4', 1000,
                         CustomObject('Fourth')),   # a custom object that corresponds to the subscription
    ])

for i in range(len(handleArray)):
    print('handleArray[', i, ']: ', handleArray[i], sep='')

print('Processing item change notifications for 1 minute...')
time.sleep(60)

print('Unsubscribing all items...')
client.UnsubscribeAllItems()

client.ItemChanged -= itemChanged

print('Finished.')
// This example shows how to store current state of the subscribed items in a dictionary.

using System;
using System.Collections.Generic;
using System.Threading;
using OpcLabs.EasyOpc.DataAccess;
using OpcLabs.EasyOpc.DataAccess.OperationModel;

namespace DocExamples.DataAccess._EasyDAClient
{
    partial class SubscribeMultipleItems
    {
        public static void StoreInDictionary()
        {
            // Instantiate the client object.
            using (var client = new EasyDAClient())
            {
                client.ItemChanged += client_ItemChanged_StoreInDictionary;

                Console.WriteLine("Subscribing item changes...");
                client.SubscribeMultipleItems(
                    new[] {
                            new DAItemGroupArguments("", "OPCLabs.KitServer.2", "Simulation.Random", 1000, null), 
                            new DAItemGroupArguments("", "OPCLabs.KitServer.2", "Trends.Ramp (1 min)", 1000, null), 
                            new DAItemGroupArguments("", "OPCLabs.KitServer.2", "Trends.Sine (1 min)", 1000, null),  
                            new DAItemGroupArguments("", "OPCLabs.KitServer.2", "Simulation.Register_I4", 1000, null)
                        });

                Console.WriteLine("Processing item changed events for 1 minute...");
                int startTickCount = Environment.TickCount;
                do
                {
                    Thread.Sleep(5*1000);

                    // Each 5 seconds, display the current state of the items we have subscribed to.
                    lock (_serialize)
                    {
                        Console.WriteLine();
                        foreach (KeyValuePair<DAItemDescriptor, DAVtqResult> pair in _vtqResultDictionary)
                        {
                            DAItemDescriptor itemDescriptor = pair.Key;
                            DAVtqResult vtqResult = pair.Value;
                            Console.WriteLine($"{itemDescriptor}: {vtqResult}");
                        }

                        // The code above shows how you can process the complete contents of the dictionary. In other
                        // scenarios, you may want to access just a specific entry in the dictionary. You can achieve that
                        // by indexing the dictionary by the item descriptor of the item you are interested in.
                    }
                } while (Environment.TickCount < startTickCount + 60*1000);

                Console.WriteLine("Unsubscribing item changes...");
            }

            Console.WriteLine("Finished.");
        }

        // Item changed event handler
        static void client_ItemChanged_StoreInDictionary(object sender, EasyDAItemChangedEventArgs e)
        {
            lock (_serialize)
                // Convert the event arguments to a DAVtq result object, and store it in the dictionary under the key which
                // is the item descriptor of the item this item changed event is for.
                _vtqResultDictionary[e.Arguments.ItemDescriptor] = (DAVtqResult)e;
        }

        // Holds last known state of each subscribed item.
        private static readonly Dictionary<DAItemDescriptor, DAVtqResult> _vtqResultDictionary = 
            new Dictionary<DAItemDescriptor, DAVtqResult>();

        // Synchronization object used to prevent simultaneous access to the dictionary.
        private static readonly object _serialize = new object();
    }
}
# This example shows how to store current state of the subscribed items in a dictionary.

# The QuickOPC package is needed. Install it using "pip install opclabs_quickopc".
import opclabs_quickopc
import threading
import time

# Import .NET namespaces.
from OpcLabs.EasyOpc.DataAccess import *
from OpcLabs.EasyOpc.DataAccess.OperationModel import *


lock = threading.Lock()
vtqResultDictionary = {}

# Item changed event handler.
def itemChanged(sender, eventArgs):
    global lock
    global vtqResultDictionary
    with lock:
        # Convert the event arguments to a DAVtq result object, and store it in the dictionary under the key which
        # is the item descriptor of the item this item changed event is for.
        vtqResultDictionary[eventArgs.Arguments.ItemDescriptor] = EasyDAItemChangedEventArgs.ToDAVtqResult(eventArgs)


# Instantiate the client object.
client = EasyDAClient()
# Hook events.
client.ItemChanged += itemChanged

print('Subscribing item changes...')
handleArray = IEasyDAClientExtension.SubscribeMultipleItems(client, [
    DAItemGroupArguments('', 'OPCLabs.KitServer.2', 'Simulation.Random', 1000, None),
    DAItemGroupArguments('', 'OPCLabs.KitServer.2', 'Trends.Ramp (1 min)', 1000, None),
    DAItemGroupArguments('', 'OPCLabs.KitServer.2', 'Trends.Sine (1 min)', 1000, None),
    DAItemGroupArguments('', 'OPCLabs.KitServer.2', 'Simulation.Register_I4', 1000, None),
    ])

for i in range(len(handleArray)):
    print('handleArray[', i, ']: ', handleArray[i], sep='')

print('Processing item change notifications for 1 minute...')
endTime = time.time() + 60
while time.time() < endTime:
    time.sleep(5)
    #
    # Each 5 seconds, display the current state of the items we have subscribed to.
    with lock:
        print()
        print('Current state of the items:')
        for itemDescriptor, vtqResult in vtqResultDictionary.items():
            print(itemDescriptor, ': ', vtqResult, sep='')
        #
        # The code above shows how you can process the complete contents of the dictionary. In other
        # scenarios, you may want to access just a specific entry in the dictionary. You can achieve that
        # by indexing the dictionary by the item descriptor of the item you are interested in.

print()
print('Unsubscribing all items...')
client.UnsubscribeAllItems()

client.ItemChanged -= itemChanged

print('Finished.')
' This example shows how to store current state of the subscribed items in a dictionary.

Imports System.Threading
Imports OpcLabs.EasyOpc.DataAccess
Imports OpcLabs.EasyOpc.DataAccess.OperationModel

Namespace DataAccess._EasyDAClient
    Partial Friend Class SubscribeMultipleItems
        Public Shared Sub StoreInDictionary()
            ' Instantiate the client object.
            Using client = New EasyDAClient()
                AddHandler client.ItemChanged, AddressOf client_ItemChanged_StoreInDictionary

                Console.WriteLine("Subscribing item changes...")
                client.SubscribeMultipleItems(New DAItemGroupArguments() {
                    New DAItemGroupArguments("", "OPCLabs.KitServer.2", "Simulation.Random", 1000, Nothing),
                    New DAItemGroupArguments("", "OPCLabs.KitServer.2", "Trends.Ramp (1 min)", 1000, Nothing),
                    New DAItemGroupArguments("", "OPCLabs.KitServer.2", "Trends.Sine (1 min)", 1000, Nothing),
                    New DAItemGroupArguments("", "OPCLabs.KitServer.2", "Simulation.Register_I4", 1000, Nothing)
                })

                Console.WriteLine("Processing item changed events for 1 minute...")
                Dim startTickCount As Integer = Environment.TickCount
                Do
                    Thread.Sleep(5 * 1000)

                    ' Each 5 seconds, display the current state of the items we have subscribed to.
                    SyncLock _serialize
                        Console.WriteLine()
                        For Each pair As KeyValuePair(Of DAItemDescriptor, DAVtqResult) In _vtqResultDictionary
                            Dim itemDescriptor As DAItemDescriptor = pair.Key
                            Dim vtqResult = pair.Value
                            Console.WriteLine($"{itemDescriptor}: {vtqResult}")
                        Next

                        ' The code above shows how you can process the complete contents of the dictionary. In other
                        ' scenarios, you may want to access just a specific entry in the dictionary. You can achieve that
                        ' by indexing the dictionary by the item descriptor of the item you are interested in.
                    End SyncLock
                Loop While Environment.TickCount < startTickCount + 60 * 1000

                Console.WriteLine("Unsubscribing item changes...")
            End Using

            Console.WriteLine("Finished.")
        End Sub

        ' Item changed event handler
        Private Shared Sub client_ItemChanged_StoreInDictionary(ByVal sender As Object, ByVal e As EasyDAItemChangedEventArgs)
            SyncLock _serialize
                ' Convert the event arguments to a DAVtq result object, and store it in the dictionary under the key which
                ' is the item descriptor of the item this item changed event is for.
                _vtqResultDictionary(e.Arguments.ItemDescriptor) = CType(e, DAVtqResult)
            End SyncLock
        End Sub

        ' Holds last known state of each subscribed item.
        Private Shared ReadOnly _vtqResultDictionary As New Dictionary(Of DAItemDescriptor, DAVtqResult)

        ' Synchronization object used to prevent simultaneous access to the dictionary.
        Private Shared ReadOnly _serialize As New Object
    End Class
End Namespace
Requirements

Target Platforms: .NET Framework: Windows 10 (selected versions), Windows 11 (selected versions), Windows Server 2016, Windows Server 2022; .NET: Linux, macOS, Microsoft Windows

See Also