Come utilizzare WPF Background Worker


177

Nella mia applicazione ho bisogno di eseguire una serie di passaggi di inizializzazione, che richiedono 7-8 secondi per il completamento durante i quali la mia UI non risponde. Per risolvere questo, eseguo l'inizializzazione in un thread separato:

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

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

Ho letto alcuni articoli su BackgroundWorkere come dovrebbe consentirmi di mantenere la mia applicazione reattiva senza mai dover scrivere un thread per eseguire compiti lunghi ma non ho avuto alcun successo nel tentativo di implementarlo, qualcuno potrebbe dire come farei questo usando il BackgroundWorker?


Ho trovato utile questo tutorial, ha diversi esempi concisi: elegantcode.com/2009/07/03/…
GrandMasterFlush

Ottengo un errore di privacy quando faccio clic su quel link.
LittleBirdy,

Risposte:


319
  1. Aggiungi utilizzando
using System.ComponentModel;
  1. Dichiarare lavoratore in background :
private readonly BackgroundWorker worker = new BackgroundWorker();
  1. Iscriviti agli eventi:
worker.DoWork += worker_DoWork;
worker.RunWorkerCompleted += worker_RunWorkerCompleted;
  1. Implementare due metodi:
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. Esegui il lavoro asincrono ogni volta che ne hai bisogno.
worker.RunWorkerAsync();
  1. Tieni traccia dei progressi (facoltativo, ma spesso utile)

    a) iscriversi alla ProgressChangedmanifestazione e l'uso ReportProgress(Int32)inDoWork

    b) impostare worker.WorkerReportsProgress = true;(crediti su @zagy)


Esiste un modo per accedere a DataContext in questi metodi?
susieloo_

36

Potresti anche voler esaminare l'utilizzo Taskanziché i lavoratori in background.

Il modo più semplice per farlo è nel tuo esempio Task.Run(InitializationThread);.

Ci sono molti vantaggi nell'uso delle attività invece dei lavoratori in background. Ad esempio, le nuove funzionalità asincrone / wait in .net 4.5 utilizzano Taskper il threading. Ecco della documentazione su Task https://docs.microsoft.com/en-us/dotnet/api/system.threading.tasks.task


11
Mi dispiace scoprire questo thread, ma .net 4.0 e 4.5 hanno aggiunto alcune cose interessanti che è molto più facile da usare di BackgroundWorker. Sperando di guidare la gente ad esso.
Owen Johnson,

1
Ora che questa risposta è super vecchia, controlla asynce await. Questi sono modi integrati nella lingua per utilizzare le attività in un modo molto più leggibile.
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);  
            }  
        }  
    }  
} 

Inoltre, fai riferimento al link seguente per comprendere i concetti di Background:

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


3

Ho trovato questo ( WPF Multithreading: utilizzo di BackgroundWorker e segnalazione dell'avanzamento all'interfaccia utente. ) Per contenere il resto dei dettagli che mancano nella risposta di @Andrea.

L'unica cosa che ho trovato molto utile era che il thread di lavoro non poteva accedere ai controlli di MainWindow (nel suo metodo), tuttavia quando si utilizzava un delegato all'interno del gestore eventi di Windows principale era possibile.

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;
};
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.