.NET中如何在UI线程触发SQLDependency事件避免跨线程重复代码
问题背景
使用SQLDependency类监听SQL Server通知时,SQLDependency.OnChange事件默认会在非UI线程执行,此时如果直接调用LoadData方法加载数据到GridView,会抛出跨线程操作错误。
目前的实现方案是将所有SQLDependency相关逻辑封装为自定义类,并在应用内全局声明该类的单实例。类内部定义了公开事件,会在SQLDependency.OnChanged事件触发时同步抛出,多个窗体都会监听该事件来重载自身对应的数据。但由于OnChange事件的触发线程是非UI线程,现在每个窗体的事件处理逻辑中都需要重复编写如下线程切换代码:
Delegate Sub ReloadCallback() Private Sub LoadOnUI() If Me.InvokeRequired Then Dim d As ReloadCallback = New ReloadCallback(AddressOf LoadOnUI) Me.Invoke(d) Else Invoke(New MethodInvoker(Sub() RefreshData())) End If End Sub
实现目标
无需在每个监听自定义事件的窗体中重复编写线程切换代码,自定义类抛出的公开事件直接在UI线程触发
解决方案
通过SynchronizationContext提前捕获UI线程上下文,在自定义类内部完成线程切换逻辑,无需上层监听的窗体处理跨线程问题:
- 确保自定义单例类在UI线程实例化(例如程序启动、主窗体初始化阶段完成实例化),在类的构造函数中捕获当前UI线程的同步上下文:
objSyncContext = SynchronizationContext.Current
- 在自定义类内部实现RunOnUIThread辅助方法,用于将指定操作投递到UI线程执行:
Delegate Sub CallDelegate() Private Sub RunOnUIThread(objEvent As CallDelegate) If objSyncContext Is Nothing Then objEvent() Else objSyncContext.Post(Sub() objEvent(), Nothing) End If End Sub
- 后续在SQLDependency.OnChange事件的处理逻辑中,不要直接触发公开的自定义事件,而是将事件触发逻辑传入RunOnUIThread执行即可。所有监听该公开事件的窗体收到回调时已经处于UI线程,直接编写数据刷新逻辑即可,无需再处理跨线程调用问题。
内容的提问来源于stack exchange,提问作者AwiringCameron
相关产品推荐
相关产品推荐

