Безопасное возбуждение событий из потока - PullRequest
1 голос
/ 15 ноября 2008

У меня есть некоторые проблемы с событиями, возникающими из потока, не являющегося пользовательским интерфейсом, в котором я не хочу обрабатывать запрос If me.invoke, требуемый для каждого обработчика событий, добавленного в поток в Form1.

Я уверен, что где-то читал, как использовать событие делегата (на SO), но я не могу его найти.

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

Ответы [ 2 ]

2 голосов
/ 15 ноября 2008

Вы вывели свой класс из Control. Немного необычно, но если элемент управления фактически размещен в форме, вы можете использовать Me.Invoke (), чтобы упорядочить вызов. Например:

  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 ():

  Private mHost As Form

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

и используйте mHost.Invoke (). Или BeginInvoke ().

Последний трюк в книге - использовать основную форму запуска в качестве объекта синхронизации. Это не совсем безопасно, но работает в 99% случаев:

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

Помните, что в WF есть ошибка, которая не позволяет OpenForms () точно отслеживать открытые формы при их динамическом воссоздании.

1 голос
/ 15 ноября 2008

Если вы хотите упростить все это, есть класс под названием BackgroundWorker, который обрабатывает маршалинг потока GUI для вас.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...