1

也许这是一个简单的问题,我只是不知道正确的搜索词来找到答案,但是我的 Google-fu 在这个问题上让我失望了。

我的 vb.net 应用程序有一个控制所有套接字通信的后台线程。有时候,我需要这个通信线程打开一个模态窗体来显示一条消息并阻塞UI交互,直到通信线程完成一系列任务,此时通信线程会移除模态窗体,让用户继续交互。

目前,我的包含后台线程的通信类有两个事件,StartBlockingTask 和 EndBlockingTask。我的主窗体具有这些事件的事件侦听器,这些事件调用同名的子程序。他们称代码如下所示:

Private Delegate Sub BlockingDelegate(ByVal reason As String)

Private Sub StartBlockingTask(ByVal reason As String)
    If Me.InvokeRequired Then
        Dim del As New BlockingDelegate(AddressOf StartBlockingTask)
        Me.Invoke(del, New Object() {reason})
    Else
        Try
            _frmBlock.lblBlock.Text = reason
            _frmBlock.ShowDialog()
        Catch ex As Exception
            'stuff
        End Try
    End If
End Sub

Private Sub EndBlockingTask()
    If Me.InvokeRequired Then
        Dim del As New BlockingDelegate(AddressOf EndBlockingTask)
        Me.Invoke(del, New Object() {""})
    Else
        Try
            If (Not _frmBlock Is Nothing) Then
                _frmBlock.DialogResult = Windows.Forms.DialogResult.OK
            End If
        Catch ex As Exception
            'stuff
        End Try
    End If
End Sub

这成功地阻止了 UI 的交互,但它也阻止了通信线程,因此 EndBlockingTask 事件实际上永远不会被引发。如何从通信线程打开此模式对话框并允许通信线程继续运行?

提前致谢!

4

2 回答 2

3

我不同意。

所需要做的就是将 Invoke() 更改为BeginInvoke(),您就可以了。

这是因为 Invoke() 实际上是同步的,这会导致它阻塞,直到 ShowDialog() 解决。

使用 BeginInvoke() 使其异步并允许 UI 在线程继续时被阻塞:

Public Class Form1

    Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
        If Not BackgroundWorker1.IsBusy Then
            BackgroundWorker1.RunWorkerAsync()
        End If
    End Sub

    Private Delegate Sub BlockingDelegate(ByVal reason As String)

    Private Sub StartBlockingTask(ByVal reason As String)
        If Me.InvokeRequired Then
            Dim del As New BlockingDelegate(AddressOf StartBlockingTask)
            Me.BeginInvoke(del, New Object() {reason})
        Else
            Try
                _frmBlock.lblBlock.Text = reason
                _frmBlock.ShowDialog()
            Catch ex As Exception
                'stuff
            End Try
        End If
    End Sub

    Private Sub EndBlockingTask()
        If Me.InvokeRequired Then
            Dim del As New BlockingDelegate(AddressOf EndBlockingTask)
            Me.BeginInvoke(del, New Object() {""})
        Else
            Try
                If (Not _frmBlock Is Nothing) Then
                    _frmBlock.DialogResult = Windows.Forms.DialogResult.OK
                End If
            Catch ex As Exception
                'stuff
            End Try
        End If
    End Sub

    Private Sub BackgroundWorker1_DoWork(sender As System.Object, e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
        For i As Integer = 1 To 10
            BackgroundWorker1.ReportProgress(i)
            System.Threading.Thread.Sleep(1000)

            If i = 4 Then
                Dim del As New BlockingDelegate(AddressOf StartBlockingTask)
                del("bada...")
            ElseIf i = 7 Then
                Dim del As New BlockingDelegate(AddressOf EndBlockingTask)
                del("bing!")
            End If
        Next
    End Sub

    Private Sub BackgroundWorker1_ProgressChanged(sender As Object, e As System.ComponentModel.ProgressChangedEventArgs) Handles BackgroundWorker1.ProgressChanged
        Label1.Text = e.ProgressPercentage
    End Sub

End Class
于 2013-06-03T19:13:36.007 回答
1

您正在从创建它的子内部调用地址。地址需要从该子外部调用。

 Private Sub StartBlockingTask(ByVal reason As String)
    If Me.InvokeRequired Then
        Dim del As New BlockingDelegate(AddressOf StartBlockingTask)


   Private Sub EndBlockingTask()
        If Me.InvokeRequired Then
            Dim del As New BlockingDelegate(AddressOf EndBlockingTask)

您需要创建两个代表。一个用于 StartBlockingTask,一个用于 EndBlockingTask

这是来自 MSDN 的示例,

Delegate Sub MySubDelegate(ByVal x As Integer)
Protected Sub Test()
   Dim c2 As New class2()
   ' Test the delegate.
   c2.DelegateTest()
End Sub

Class class1
   Sub Sub1(ByVal x As Integer)
      MessageBox.Show("The value of x is: " & CStr(x))
   End Sub
End Class

Class class2
   Sub DelegateTest()
      Dim c1 As Class1
      Dim msd As MySubDelegate
      c1 = New Class1()
      ' Create an instance of the delegate.
      msd = AddressOf c1.Sub1
      msd.Invoke(10) ' Call the method.
   End Sub
End Class

http://msdn.microsoft.com/en-us/library/5t38cb9x(v=vs.71).aspx

让我知道这是否有帮助。

于 2013-06-03T16:20:24.933 回答