.NET Based OPC UA Client/Server SDK  3.3.0.530
Data Access

Changing values in the model

Unlike to the LinkModelToNode mechanism, the model will not be accessed on client read or monitor requests. The current value of a node is stored in the memory node itself. In order for the server to notice when something changes in the model, the model should implement the INotfiyPropertyChanged interface. The ModelControllerBase supports the interface with the SetField method. An example how a property should look like can be found, for example, in the TemperingInstructionModel.

[UaInstanceDeclaration(NamespaceUri = Namespaces.MachineDemoServer)]
public GlassTemperingPlan LoadedPlan
{
get => m_LoadedPlan;
set => SetField(ref m_LoadedPlan, value, nameof(LoadedPlan));
}
private GlassTemperingPlan m_LoadedPlan;

Usually, the UaModeler will generate properties for the NodeSet relevant the variables and properties. The user of the model will than just retrieve the value from the model or set it to the model. As be shown in the HeaterModel:

Temperature.Value = temperature;

Changes from the client

When a client writes a value into a model related node, this value will be first set to the model. The model will than raise a property changed event and the server can update its node value. If you want to react inside of the model on changes you can subscribe yourself to the property change event. In the heater model you'll find an example.

TemperatureSetpoint.PropertyChanged += (o, e) =>
{
switch (e.PropertyName)
{
case nameof(TemperatureSetpoint.Value):
Console.WriteLine($"[{Thread.CurrentThread.ManagedThreadId}] TemperatureSetpoint changed to {TemperatureSetpoint.Value}");
break;
}
};

Sometimes one wants to restrict the possible value range that a client can write or apply some further validation on the value before the value is actually set to the model. This can be achieved by the PropertyChangeRequested. The heater, for example, will clamp negative value to 0°C and will reject temperatures above 500°C.

TemperatureSetpoint.PropertyChangeRequested += (o, e) =>
{
switch (e.PropertyName)
{
case nameof(TemperatureSetpoint.Value):
var value = (double)e.Value;
Console.WriteLine($"[{Thread.CurrentThread.ManagedThreadId}] TemperatureSetpoint change request to {value}");
if (double.IsNaN(value) || value > 500.0)
{
e.StatusCode = StatusCodes.BadOutOfRange;
}
else if (value < 0.0)
{
e.StatusCode = StatusCodes.GoodClamped;
e.Value = 0.0;
}
break;
}
};