C# WinForm中WebSocket OnMessage监听内向ListView添加项异常
问题根因
抛出System.InvalidOperationException、ListView不更新是典型的跨线程访问UI控件违规:
- WebSocket的
OnMessage回调运行在独立的后台工作线程,而非UI主线程 - WinForm的所有UI控件都有线程亲和性,只能在创建控件的UI主线程上执行修改操作,后台线程直接操作控件就会触发该异常,和控制台能正常输出数据不冲突——控制台输出没有线程限制。
修复代码
通过控件自带的线程封送方法,把ListView更新逻辑投递到UI主线程执行即可,修改后的回调代码:
private void Ws_OnMessage(object sender, MessageEventArgs e) { dynamic data = JsonConvert.DeserializeObject<dynamic>(e.Data); double price = data["data"][0]["p"]; string stock = data["data"][0]["s"]; Console.WriteLine($"{stock} {price}"); // 跨线程判断 if (portfolioList.InvokeRequired) { // 异步封送到UI线程执行更新,不阻塞WebSocket消息接收 portfolioList.BeginInvoke((Action)(() => { var item = new ListViewItem(new[] { stock, price.ToString() }); portfolioList.Items.Add(item); })); return; } // 处于UI线程时直接更新 var uiItem = new ListViewItem(new[] { stock, price.ToString() }); portfolioList.Items.Add(uiItem); }
注意点
- 不要在
OnMessage回调里直接写UI更新逻辑,所有涉及界面控件修改的代码都要做跨线程检查 - 优先用
BeginInvoke做异步封送,避免阻塞WebSocket的消息接收线程导致消息堆积;如果需要同步拿到UI更新结果再做后续处理,再使用Invoke - 如果项目是WPF框架,替换成
Dispatcher.BeginInvoke做线程封送即可,核心逻辑一致。
内容的提问来源于stack exchange,提问作者Ajax21
相关产品推荐
相关产品推荐

