跳到主要内容

Events — ua.Events.*

DarraOpcUa.Events 是 SDK 内部事件统一通道, 把会话生命周期 / 订阅生命周期 / 数据变化 / 通讯异常都汇集到一个对象上, 方便上层 UI 做日志 / 状态栏 / 调试.

与 OPC UA 协议事件区分
  • ua.Events.* — SDK 内部事件 (本节, 与协议无关)
  • ua.SubscribeEvents(...) — OPC UA 协议事件 (Alarms & Conditions), 见 事件订阅

完整事件清单

会话生命周期

  • Connected (EndpointUrl, Status) — 首次连接成功
  • Disconnected (EndpointUrl, Status, Reason) — 主动 / 被动断开
  • Reconnecting (EndpointUrl) — 检测到断线, 启动自动重连
  • Reconnected (EndpointUrl) — 自动重连成功
  • KeepAlive (Timestamp, Status) — KeepAlive 心跳成功
  • StateChanged (OldState, NewState, Reason) — 任何 SessionState 变化

订阅生命周期

  • ServerEvent(SubscriptionCreated, ...) — CreateSubscription 成功
  • ServerEvent(MonitoredItemAdded, ...) — sub.Add 成功
  • ServerEvent(MonitoredItemRemoved, ...) — sub.Remove 成功
  • ServerEvent(SubscriptionLost, ...) — 订阅被服务端清理
  • ServerEvent(SubscriptionRestored, ...) — TransferSubscriptions 后恢复

数据 / 服务器

  • DataChange (sub, nodeId, valueString, status) — 任何订阅 DataChange (统一通道, 与 sub.DataChanged 双发)
  • ServerEvent (category, severity, source, msg, statusCode) — 内部 Read / Write / Browse / Call / HistoryRead 等操作

异常

  • CommunicationError (StatusCode, where, msg) — 通讯失败 (KeepAlive 失败 / Read 异常等)
  • SecurityError (StatusCode, msg) — 加密 / 证书相关错误

OpcUaEventCategory 枚举

ServerEvent 第一个参数是 Category, 完整清单:

Connected, Disconnected, Reconnecting, Reconnected, KeepAlive, StateChanged,
SubscriptionCreated, SubscriptionLost, SubscriptionRestored,
MonitoredItemAdded, MonitoredItemRemoved, SubscriptionCleared,
DataChange, ServerEvent, Alarm,
Read, Write, Browse, Call, HistoryRead,
CommunicationError, SecurityError, ProtocolError,
Info, Diagnostic,

// 节点 / 会话级新增分类 (2026-04-25)
NodeRemoved = 30, // 服务端删除了某节点 (Browse/Read/订阅 收到 BadNodeIdUnknown)
NodeAccessDenied = 31, // 用户对该节点权限不足 (BadUserAccessDenied)
NodeTypeChanged = 32, // 节点 DataType 变了 (Write 时 BadTypeMismatch)
SessionLost = 33, // Session 断开 (BadSessionClosed/BadSessionIdInvalid, 重连前)
ServerStateChanged = 34 // 服务端 Running → Failed/Shutdown/Test 等

Typed 通道 (语法糖) — 6 个新事件

除了 Any 统一通道, 6 个高频 Category 提供专属事件, UI 不必每条事件先 if Category==X 过滤:

事件Category触发场景
NodeRemovedNodeRemoved命中 BadNodeIdUnknown, 节点已被服务端删
NodeAccessDeniedNodeAccessDenied命中 BadUserAccessDenied
NodeTypeChangedNodeTypeChangedWrite 时命中 BadTypeMismatch
SessionLostSessionLostSession 失效 (重连前预警)
ServerStateChangedServerStateChanged服务端状态切换
SubscriptionRestoredSubscriptionRestored订阅恢复成功 (Transfer / Recreate)

每个 typed 事件的回调签名都是 EventHandler<OpcUaEventEntry>, 参数携带 NodeId / StatusCode / Source / Message

ua.Events.NodeRemoved += (s, e) =>
{
Console.WriteLine($"⚠ 节点已被服务端删除: {e.Source} ({e.StatusCode})");
treeView.RemoveNode(e.Source);
};

ua.Events.NodeAccessDenied += (s, e) =>
{
Console.WriteLine($"⛔ 权限不足: {e.Source}");
};

ua.Events.SessionLost += (s, e) =>
{
statusBar.Text = "⚠ 会话失效, 即将重连...";
};

ua.Events.ServerStateChanged += (s, e) =>
{
Console.WriteLine($"服务端状态: {e.Message}");
};

ua.Events.SubscriptionRestored += (s, e) =>
{
Console.WriteLine($"订阅已恢复: {e.Source}");
};

详见 自动重连订阅自恢复

OpcUaEventSeverity 枚举

Trace, Debug, Info, Warn, Error, Fatal

用法示例

通用日志钩子 (一行打印 SDK 内所有事件)

ua.Events.ServerEvent += (s, e) =>
{
Console.WriteLine($"[{e.Severity}] [{e.Category}] {e.Source}: {e.Message} ({e.Status})");
};

调试期非常省事 — 不订阅具体事件, 一行 hook 看全部.

状态栏绑定 (WPF)

ua.Events.StateChanged += (s, e) =>
{
Dispatcher.Invoke(() =>
{
statusLabel.Text = $"{e.NewState}";
statusLabel.Foreground = e.NewState == SessionState.Connected
? Brushes.Green : Brushes.Red;
});
};

错误统计

int errorCount = 0;
ua.Events.CommunicationError += (s, e) => Interlocked.Increment(ref errorCount);

与订阅 DataChanged 的关系

订阅 sub.DataChanged 仅收到该订阅的事件; ua.Events.DataChange 收到 SDK 下所有订阅的事件 (统一通道). 两者并存, 上层按场景选用:

  • 单订阅业务逻辑 → sub.DataChanged
  • 全局日志 / 录波 / 调试 → ua.Events.DataChange

线程模型

必须切回 UI 线程

事件回调在 C 层 Publish 线程上调用, 不在调用方线程. UI 操作必须 Dispatcher.Invoke / this.Invoke 切回 UI 线程, 否则跨线程 UI 操作抛 InvalidOperationException.

不要在事件里执行长操作 (>100 ms), 否则会阻塞 Publish 队列.

下一步