C#等待线程完成而不阻塞UI [重复]

Posted

技术标签:

【中文标题】C#等待线程完成而不阻塞UI [重复]【英文标题】:C# wait for thread to finish without blocking UI [duplicate] 【发布时间】:2021-05-19 18:56:36 【问题描述】:
        checkerThread = new Thread(new ThreadStart(() => CheckTokens()));
        checkerThread.Start();

        // Re-enable controls when done
        stopCheckButton.Visible = false;
        stopCheckButton.Enabled = false;
        startCheckButton.Enabled = true;
        loadTokenListButton.Enabled = true;
        exportTokensButton.Enabled = true;
        clearCheckButton.Enabled = true;
        clearValidButton.Enabled = true;
        tokenInputBox.Enabled = true;

当线程运行时,我的表单中的控件被禁用。我想在线程完成后重新启用它们。在不被thread.Join() 阻塞用户界面的情况下,我该怎么做?

【问题讨论】:

你听说过异步/等待吗? 使用 async / await 取决于 imo 必须完成的工作类型。 BackgroundWorker 在工具箱中,您会喜欢它的 RunWorkerCompleted 事件。 记住 - “await” 可能像病毒:它可以用愚蠢的“Async”声明“感染”代码库中不相关的部分。 @paulsm4 不,它只会影响代码库的相关部分,即任何关心异步操作完成时执行操作的部分。而且这个问题并不特定于 async 作为关键字,它是异步操作所固有的,即使您使用其他形式的异步,也必须不阻塞 UI。 【参考方案1】:

我建议考虑使用BackgroundWorker

示例代码:

https://docs.microsoft.com/en-us/dotnet/desktop/winforms/controls/how-to-run-an-operation-in-the-background?view=netframeworkdesktop-4.8

这是另一个例子:

https://www.dotnetperls.com/backgroundworker-vbnet

public Class Form1

    Public Class ArgumentType
        Public _a As Int32
        Public _b As Int32
    End Class

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        ' Create the argument object.
        Dim args As ArgumentType = New ArgumentType()
        args._a = 5
        args._b = 6
        ' Start up the BackgroundWorker1.
        ' ... Pass argument object to it.
        BackgroundWorker1.RunWorkerAsync(args)
    End Sub

    Private Sub BackgroundWorker1_DoWork(ByVal sender As System.Object, _
                                         ByVal e As System.ComponentModel.DoWorkEventArgs) _
                                         Handles BackgroundWorker1.DoWork
        ' Do some time-consuming work on this thread.
        System.Threading.Thread.Sleep(1000)
        ' Get argument.
        Dim args As ArgumentType = e.Argument
        ' Return value based on the argument.
        e.Result = args._a * args._b
    End Sub

    Private Sub BackgroundWorker1_RunWorkerCompleted(ByVal sender As System.Object, _
                                                     ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) _
                                                     Handles BackgroundWorker1.RunWorkerCompleted
        ' Called when the BackgroundWorker is completed.
        MessageBox.Show(e.Result.ToString())
    End Sub
End Class

【讨论】:

@Janic - 正如 Frederik Gheysels 所说,“使用 async / await 取决于 imo 必须完成的工作类型”。我认为 BackgroudWorker 可能更适合您的需求。问:您在标题中说“C#”……但在标签中说 VB.Net。它是哪一个?这两个例子都应该很容易翻译成任何一种语言:) @Janic 如果您要学习一些东西,请不要学习过时的后台工作者。学习异步/等待。 @paulsm4 await 是比 BGW 更的通用工具。 await 可以做 BGW 可以做的一切,BGW 不能做 await 可以做的一切。如果这是一个BGW 根本不适合的问题,你只能用await 解决问题,而不是等待对Task.Run 的一次调用。 @Janic - 我相信“更新”不一定是“更好”。 BackgroundWorker 在这里非常合适。并且“等待”可以像病毒一样:它可以用其他不必要的“异步”声明“感染”代码库中不相关的部分。如果有帮助,请考虑“支持”和/或“接受”此回复。

以上是关于C#等待线程完成而不阻塞UI [重复]的主要内容,如果未能解决你的问题,请参考以下文章

等待QThread时UI会阻塞/如何正确使用QThread

如何在多个任务之后继续而不阻塞 UI 线程?

在任务期间显示进度对话框而不阻塞Android中的UI线程

java 多次new DataOutputStream而不关闭,线程阻塞

写入 coredata,即使在后台线程上完成,也会严重阻塞 UI

异步/同步/阻塞/非阻塞