UI线程上的.NET引发事件[重复]
Posted
技术标签:
【中文标题】UI线程上的.NET引发事件[重复]【英文标题】:.NET raise event on UI thread [duplicate] 【发布时间】:2021-12-09 18:53:43 【问题描述】:我正在使用SQLDependency 类来侦听SQL 通知,并且SQLDependency.OnChange 事件在与UI 线程不同的线程上执行。我的目的是在触发此事件时更新网格视图中的数据,以便 SQL Server 数据库更改可以立即反映在网格中。
如果我运行 LoadData
方法将数据重新加载到网格中,则会出现跨线程错误:
我创建了一个自定义类来保存所有与 SQLDependency 相关的代码,并且在我的应用程序中全局声明了该类的一个实例。我在SQLDependency.OnChanged 事件中引发的类上有一个事件。然后在各种不同的表单上处理此事件,以便可以重新加载它们的数据。但是,因为OnChange 事件是在不同的线程上引发的,所以我需要先添加运行逻辑:
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
我希望避免重复此代码并将其复制到每个处理我的自定义事件的位置。 This answer 几乎正是我正在寻找的东西,但我不知道如何实现提供的代码。
逻辑如下,获取事件的调用列表并获取其中一个处理程序的线程,然后在该线程上引发事件。以我有限的经验,我无法自己编写代码来做到这一点。任何帮助将不胜感激。
目标:在 UI 线程上引发一个事件,而不在事件处理程序中重复额外的代码。
解决方案: 提前在目标线程上运行此代码(例如类构造函数)。
objSyncContext = SynchronizationContext.Current
从另一个线程调用此方法RunOnUIThread(AddressOf RefreshData)
以在目标线程上运行引用的方法。
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
【问题讨论】:
***.com/a/27365255/17034 github.com/dotnet/reactive 【参考方案1】:这是一个使用 SynchronizationContext 的简单示例。
请注意,它假定您是从主 UI 线程创建类,并从构造函数存储当前上下文:
Public Class Form1
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim d As New Duck("Bob")
AddHandler d.Quack, AddressOf duck_Quack
Label1.Text = "Waiting for Quack..."
d.RaiseThreadedQuack(3)
End Sub
Private Sub duck_Quack(source As Duck)
Label1.Text = "Quack received from: " & source.Name
End Sub
End Class
Public Class Duck
Public ReadOnly Property Name() As String
Private sc As WindowsFormsSynchronizationContext
Public Sub New(ByVal name As String)
Me.Name = name
sc = WindowsFormsSynchronizationContext.Current
End Sub
Public Event Quack(ByVal source As Duck)
Public Sub RaiseThreadedQuack(ByVal delayInSeconds As Integer)
Dim T As New Threading.Thread(AddressOf ThreadedQuack)
T.Start(delayInSeconds)
End Sub
Private Sub ThreadedQuack(ByVal O As Object)
System.Threading.Thread.Sleep(TimeSpan.FromSeconds(O).TotalMilliseconds)
sc.Post(AddressOf RaiseUIQuack, Me)
End Sub
Private Sub RaiseUIQuack(ByVal O As Object)
RaiseEvent Quack(O)
End Sub
End Class
【讨论】:
以上是关于UI线程上的.NET引发事件[重复]的主要内容,如果未能解决你的问题,请参考以下文章