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 | 触发场景 |
|---|---|---|
| NodeRemoved | NodeRemoved | 命中 BadNodeIdUnknown, 节点已被服务端删 |
| NodeAccessDenied | NodeAccessDenied | 命中 BadUserAccessDenied |
| NodeTypeChanged | NodeTypeChanged | Write 时命中 BadTypeMismatch |
| SessionLost | SessionLost | Session 失效 (重连前预警) |
| ServerStateChanged | ServerStateChanged | 服务端状态切换 |
| SubscriptionRestored | SubscriptionRestored | 订阅恢复成功 (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 队列.