安全地从线程引发事件 [英] Raising Events from a thread safely

查看:44
本文介绍了安全地从线程引发事件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在从非UI线程引发事件时遇到一些问题,因为我不想处理在Form1中添加到线程的每个事件处理程序上的If me.invokerequired.

I am having some problems with events being raised from the non-UI thread, in that i dont wish to have to handle the If me.invokerequired on every event handler added to the thread in Form1.

我确定我已经在某处阅读了如何使用委托事件,但是我找不到它.

I am sure i have read somewhere how to use a delegate event (on SO) but i am unable to find it.

Public Class Form1

    Private WithEvents _to As New ThreadedOperation

    Private Sub Button_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button.Click
        _to.start()
    End Sub

    Private Sub _to_SomthingHappend(ByVal result As Integer) Handles _to.SomthingHappend
        TextBox.Text = result.ToString //cross thread exception here
    End Sub

End Class

Public Class ThreadedOperation

    Public Event SomthingHappend(ByVal result As Integer)
    Private _thread As Threading.Thread

    Public Sub start()
        If _thread Is Nothing Then
            _thread = New Threading.Thread(AddressOf Work)
        End If
        _thread.Start()
    End Sub

    Private Sub Work()
        For i As Integer = 0 To 10
            RaiseEvent SomthingHappend(i)
            Threading.Thread.Sleep(500)
        Next
    End Sub

End Class

推荐答案

您从Control派生了您的课程.有点不寻常,但是如果控件实际上托管在窗体上,则可以使用Me.Invoke()封送调用.例如:

You derived your class from Control. A bit unusual, but if the control is actually hosted on a form, you can use Me.Invoke() to marshal the call. For example:

  Private Delegate Sub SomethingHappenedDelegate(ByVal result As Integer)

  Private Sub Work()
    For i As Integer = 0 To 10
      Me.Invoke(New SomethingHappenedDelegate(AddressOf SomethingHappenedThreadSafe), i)
      Threading.Thread.Sleep(500)
    Next
  End Sub

  Private Sub SomethingHappenedThreadSafe(ByVal result As Integer)
    RaiseEvent SomthingHappend(result)
  End Sub

如果该类对象实际上未托管在表单上,​​则需要传递对该表单的引用,以便它可以调用Invoke():

If this class object is not actually hosted on a form, you'll need to pass a reference to the form so it can call Invoke():

  Private mHost As Form

  Public Sub New(ByVal host As Form)
    mHost = host
  End Sub

并使用mHost.Invoke().或BeginInvoke().

and use mHost.Invoke(). Or BeginInvoke().

这本书的最后一个技巧是将您的主要启动表单用作同步对象.这并不完全安全,但可以在99%的情况下起作用:

The last trick in the book is to use your main startup form as the synchronization object. That's not completely safe but works in 99% of the case:

  Dim main As Form = Application.OpenForms(0)
  main.Invoke(New SomethingHappenedDelegate(AddressOf SomethingHappenedThreadSafe), i)

请注意,WF中存在一个错误,该错误会阻止OpenForms()在动态重新创建打开的表单时准确地跟踪它们.

Beware that there's a bug in WF that prevents OpenForms() from accurately tracking open forms when they get dynamically recreated.

这篇关于安全地从线程引发事件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆