从后台线程打开模式窗体以阻止UI线程,同时也不会阻止后台线程 [英] Open a modal form from a background thread to block UI thread without also blocking background thread

查看:115
本文介绍了从后台线程打开模式窗体以阻止UI线程,同时也不会阻止后台线程的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

也许这是一个简单的问题,我只是不知道正确的搜索词来找到答案,但是我的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屋!

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