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引发事件[重复]的主要内容,如果未能解决你的问题,请参考以下文章

关于 SWT 的UI线程和非UI线程

子线程中如何修改ui界面

如何从工作线程中调用 UI 线程上的方法? [复制]

从第二个线程引发事件到主线程,没有表单[重复]

为啥在 UI 线程上输入锁会触发 OnPaint 事件?

ios开发在子线程更新ui会怎样