Cách sử dụng WPF Background Worker


177

Trong ứng dụng của mình, tôi cần thực hiện một loạt các bước khởi tạo, những bước này mất 7-8 giây để hoàn thành trong đó UI của tôi không phản hồi. Để giải quyết vấn đề này, tôi thực hiện khởi tạo trong một luồng riêng biệt:

public void Initialization()
{
    Thread initThread = new Thread(new ThreadStart(InitializationThread));
    initThread.Start();
}

public void InitializationThread()
{
    outputMessage("Initializing...");
    //DO INITIALIZATION
    outputMessage("Initialization Complete");
}

Tôi đã đọc một vài bài viết về BackgroundWorkervà cách nó cho phép tôi giữ cho ứng dụng của mình phản ứng nhanh mà không cần phải viết một luồng để thực hiện các tác vụ dài nhưng tôi chưa có thành công nào khi thử thực hiện nó, bất cứ ai cũng có thể biết tôi sẽ làm như thế nào này bằng cách sử dụng BackgroundWorker?


Tôi tìm thấy hướng dẫn này hữu ích, nó có một số ví dụ ngắn gọn: elegantcode.com/2009/07/03/...
GrandMasterFlush

Tôi nhận được lỗi riêng tư khi nhấp vào liên kết đó.
LittleBirdy

Câu trả lời:


319
  1. Thêm sử dụng
using System.ComponentModel;
  1. Khai báo công nhân nền :
private readonly BackgroundWorker worker = new BackgroundWorker();
  1. Theo dõi các sự kiện:
worker.DoWork += worker_DoWork;
worker.RunWorkerCompleted += worker_RunWorkerCompleted;
  1. Thực hiện hai phương pháp:
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
}
  1. Chạy worker async bất cứ khi nào bạn cần.
worker.RunWorkerAsync();
  1. Theo dõi tiến trình (tùy chọn, nhưng thường hữu ích)

    a) đăng ký ProgressChangedsự kiện và sử dụng ReportProgress(Int32)trongDoWork

    b) đặt worker.WorkerReportsProgress = true;(tín dụng cho @zagy)


Có cách nào để truy cập DataContext trong các phương thức đó không?
susieloo_

36

Bạn cũng có thể muốn xem xét sử dụng Taskthay vì nhân viên nền.

Cách dễ nhất để làm điều này là trong ví dụ của bạn là Task.Run(InitializationThread);.

Có một số lợi ích khi sử dụng các tác vụ thay vì nhân viên nền. Ví dụ: các tính năng async / await mới trong .net 4.5 sử dụng Taskcho luồng. Dưới đây là một số tài liệu về Task https://docs.microsoft.com/en-us/dotnet/api/system.threading.t task.task


11
Xin lỗi để khai quật chủ đề này, nhưng .net 4.0 và 4.5 đã thêm một số nội dung thú vị dễ sử dụng hơn BackgroundWorker. Hy vọng để chỉ đạo mọi người với nó.
Owen Johnson

1
Bây giờ câu trả lời này là siêu cũ, hãy kiểm tra asyncawait. Đây là những cách tích hợp ngôn ngữ để sử dụng các tác vụ theo cách dễ đọc hơn nhiều.
Owen Johnson

14
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);  
            }  
        }  
    }  
} 

Ngoài ra, hãy tham khảo liên kết dưới đây bạn sẽ hiểu các khái niệm về Background:

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


3

Tôi đã tìm thấy điều này ( Đa luồng WPF: Sử dụng liên kết BackgroundWorker và báo cáo tiến trình tới giao diện người dùng. ) Để chứa phần còn lại của các chi tiết còn thiếu trong câu trả lời của @ Andrew.

Một điều tôi thấy rất hữu ích là luồng công nhân không thể truy cập các điều khiển của MainWindow (theo phương thức riêng của nó), tuy nhiên khi sử dụng một đại biểu bên trong trình xử lý sự kiện windows chính thì có thể.

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;
};
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.