从后台线程打开模式窗体以阻止UI线程,同时也不会阻止后台线程 [英] Open a modal form from a background thread to block UI thread without also blocking background thread
问题描述
也许这是一个简单的问题,我只是不知道正确的搜索词来找到答案,但是我的Google-fu在这个问题上使我失败了.
Maybe this is a simple question and I just don't know the correct search terms to find the answer, but my Google-fu has failed me on this one.
我的vb.net应用程序具有控制所有套接字通信的后台线程.有时,我需要此通信线程来打开模式形式以显示消息并阻止UI交互,直到通信线程完成一系列任务为止,此时通信线程将删除模式形式,从而允许用户继续进行交互.
My vb.net application has a background thread that controls all the socket communication. Occasionally, I need this communication thread to open up a modal form to display a message and block UI interaction until the communication thread completes a series of tasks at which point, the communication thread will remove the modal form, allowing the user to continue interaction.
当前,我的包含后台线程的通信类有两个事件,StartBlockingTask和EndBlockingTask.我的主窗体具有用于这些事件的事件侦听器,这些事件侦听器调用了具有相同名称的子程序.他们以如下方式调用代码:
Currently, my communications class containing the background thread has two events, StartBlockingTask and EndBlockingTask. My main form has event listeners for these events that call like-named subs. They call code looking like this:
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事件从未真正引发.如何从通讯线程中打开此模式对话框,并允许通讯线程继续运行?
This successfully blocks the UI from interaction, but it also blocks the communications thread so the EndBlockingTask event never actually gets raised. How can I open this modal dialog from the communications thread and allow the communications thread to still continue running?
提前谢谢!
推荐答案
我不同意.
所有需要做的就是将Invoke()更改为 BeginInvoke(),这样您就很开心了.
All that needs to be done is to change Invoke() to BeginInvoke() and you're golden.
这是因为Invoke()实际上是同步的,这导致它一直阻塞,直到ShowDialog()解析为止.
This is because Invoke() is actually synchronous which causes it block until ShowDialog() resolves.
使用BeginInvoke()使其异步,并允许在线程继续执行时阻止UI:
Using BeginInvoke() makes it asynchronous and allows the UI to be blocked while the thread continues:
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
这篇关于从后台线程打开模式窗体以阻止UI线程,同时也不会阻止后台线程的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!