如何使用 WPF 后台工作者

Posted

技术标签:

【中文标题】如何使用 WPF 后台工作者【英文标题】:How to use WPF Background Worker 【发布时间】:2011-07-25 21:49:49 【问题描述】:

在我的应用程序中,我需要执行一系列初始化步骤,这些步骤需要 7-8 秒才能完成,在此期间我的 UI 变得无响应。为了解决这个问题,我在一个单独的线程中执行初始化:

public void Initialization()

    Thread initThread = new Thread(new ThreadStart(InitializationThread));
    initThread.Start();


public void InitializationThread()

    outputMessage("Initializing...");
    //DO INITIALIZATION
    outputMessage("Initialization Complete");

我已经阅读了几篇关于 BackgroundWorker 的文章,以及它应该如何让我的应用程序保持响应,而无需编写线程来执行冗长的任务,但我没有成功尝试实现它,可以有人告诉我如何使用BackgroundWorker 做到这一点?

【问题讨论】:

我发现这个教程很有用,它有几个简洁的例子:elegantcode.com/2009/07/03/… 点击该链接时出现隐私错误。 【参考方案1】:
    使用添加
using System.ComponentModel;
    声明Background Worker:
private readonly BackgroundWorker worker = new BackgroundWorker();
    订阅活动:
worker.DoWork += worker_DoWork;
worker.RunWorkerCompleted += worker_RunWorkerCompleted;
    实现两种方法:
private void worker_DoWork(object sender, DoWorkEventArgs e)

  // run all background tasks here


private void worker_RunWorkerCompleted(object sender, 
                                           RunWorkerCompletedEventArgs e)

  //update ui once worker complete his work

    根据需要运行工作程序异步。
worker.RunWorkerAsync();

    跟踪进度(可选,但通常很有用)

    a) 订阅ProgressChanged 事件并在DoWork 中使用ReportProgress(Int32)

    b) 设置worker.WorkerReportsProgress = true;(归功于@zagy)

【讨论】:

有没有办法在这些方法中访问 DataContext?【参考方案2】:

您可能还想考虑使用 Task 而不是后台工作人员。

在您的示例中,最简单的方法是Task.Run(InitializationThread);

使用任务而不是后台工作人员有几个好处。例如,.net 4.5 中的新 async/await 功能使用Task 进行线程处理。这是一些关于Task 的文档 https://docs.microsoft.com/en-us/dotnet/api/system.threading.tasks.task

【讨论】:

很抱歉发现了这个帖子,但是.net 4.0 和 4.5 添加了一些很酷的东西,比BackgroundWorker 更容易使用。希望引导人们走向它。 现在这个答案已经很老了,请查看asyncawait。这些是以更易读的方式使用任务的语言集成方式。【参考方案3】:
using System;  
using System.ComponentModel;   
using System.Threading;    
namespace BackGroundWorkerExample  
   
    class Program  
      
        private static BackgroundWorker backgroundWorker;  

        static void Main(string[] args)  
          
            backgroundWorker = new BackgroundWorker  
              
                WorkerReportsProgress = true,  
                WorkerSupportsCancellation = true  
            ;  

            backgroundWorker.DoWork += backgroundWorker_DoWork;  
            //For the display of operation progress to UI.    
            backgroundWorker.ProgressChanged += backgroundWorker_ProgressChanged;  
            //After the completation of operation.    
            backgroundWorker.RunWorkerCompleted += backgroundWorker_RunWorkerCompleted;  
            backgroundWorker.RunWorkerAsync("Press Enter in the next 5 seconds to Cancel operation:");  

            Console.ReadLine();  

            if (backgroundWorker.IsBusy)  
             
                backgroundWorker.CancelAsync();  
                Console.ReadLine();  
              
          

        static void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)  
          
            for (int i = 0; i < 200; i++)  
              
                if (backgroundWorker.CancellationPending)  
                  
                    e.Cancel = true;  
                    return;  
                  

                backgroundWorker.ReportProgress(i);  
                Thread.Sleep(1000);  
                e.Result = 1000;  
              
          

        static void backgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)  
          
            Console.WriteLine("Completed" + e.ProgressPercentage + "%");  
          

        static void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)  
          

            if (e.Cancelled)  
              
                Console.WriteLine("Operation Cancelled");  
              
            else if (e.Error != null)  
              
                Console.WriteLine("Error in Process :" + e.Error);  
              
            else  
              
                Console.WriteLine("Operation Completed :" + e.Result);  
              
          
      
 

另外,参考下面的链接你会明白Background的概念:

http://www.c-sharpcorner.com/UploadFile/1c8574/threads-in-wpf/

【讨论】:

【参考方案4】:

我发现这个 (WPF Multithreading: Using the BackgroundWorker and Reporting the Progress to the UI. link) 包含 @Andrew 的答案中缺少的其他详细信息。

我发现非常有用的一件事是工作线程无法访问 MainWindow 的控件(在它自己的方法中),但是在主窗口事件处理程序中使用委托时这是可能的。

worker.RunWorkerCompleted += delegate(object s, RunWorkerCompletedEventArgs args)

    pd.Close();
    // Get a result from the asynchronous worker
    T t = (t)args.Result
    this.ExampleControl.Text = t.BlaBla;
;

【讨论】:

以上是关于如何使用 WPF 后台工作者的主要内容,如果未能解决你的问题,请参考以下文章

WPF中style中定义的控件如何里面包含一个checkbox控件,我想在后台c#代码中使用该控件,代码如何写?

c# - 如何强制关闭运行它自己的线程的后台工作者

如何使后台工作线程之间的事件在自己的上下文中执行

wpf 设置控件的显示时间

wpf 如何获取控件的x:Name

WPF后台如何获得前台XAML中对象