Comment utiliser WPF Background Worker

177

Dans mon application, je dois effectuer une série d'étapes d'initialisation, qui prennent entre 7 et 8 secondes, pendant lesquelles mon interface utilisateur ne répond plus. Pour résoudre ce problème, j'effectue l'initialisation dans un thread séparé:

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

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

J'ai lu quelques articles sur le BackgroundWorkeret comment cela devrait me permettre de garder mon application réactive sans jamais avoir à écrire un fil pour effectuer de longues tâches, mais je n'ai pas eu de succès en essayant de l'implémenter, quelqu'un pourrait-il dire comment je ferais ceci en utilisant le BackgroundWorker?

Eamonn McEvoy
la source
J'ai trouvé ce tutoriel utile, il a plusieurs exemples concis: elegantcode.com/2009/07/03/…
GrandMasterFlush
J'obtiens une erreur de confidentialité en cliquant sur ce lien.
LittleBirdy

Réponses:

319
  1. Ajouter en utilisant
using System.ComponentModel;
  1. Déclarer l'agent d' arrière-plan :
private readonly BackgroundWorker worker = new BackgroundWorker();
  1. Abonnez-vous aux événements:
worker.DoWork += worker_DoWork;
worker.RunWorkerCompleted += worker_RunWorkerCompleted;
  1. Implémentez deux méthodes:
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. Exécutez worker async chaque fois que vous en avez besoin.
worker.RunWorkerAsync();
  1. Suivre les progrès (facultatif, mais souvent utile)

    a) s'abonner à l' ProgressChangedévénement et l'utiliser ReportProgress(Int32)dansDoWork

    b) set worker.WorkerReportsProgress = true;(crédits à @zagy)

Andrew Orsich
la source
Existe-t-il un moyen d'accéder au DataContext dans ces méthodes?
susieloo_
36

Vous voudrez peut-être également envisager d'utiliser Taskau lieu de travailleurs d'arrière-plan.

Le moyen le plus simple de le faire est dans votre exemple Task.Run(InitializationThread);.

Il y a plusieurs avantages à utiliser des tâches au lieu de travailleurs d'arrière-plan. Par exemple, les nouvelles fonctionnalités async / await de .net 4.5 sont utilisées Taskpour le threading. Voici une documentation sur Task https://docs.microsoft.com/en-us/dotnet/api/system.threading.tasks.task

Owen Johnson
la source
11
Désolé de dénicher ce fil, mais .net 4.0 et 4.5 ont ajouté des trucs sympas qui sont bien plus faciles à utiliser que BackgroundWorker. En espérant y diriger les gens.
Owen Johnson
1
Maintenant que cette réponse est très ancienne, consultez asyncet await. Ce sont des moyens intégrés dans le langage pour utiliser les tâches de manière beaucoup plus lisible.
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);  
            }  
        }  
    }  
} 

Aussi, référez-vous au lien ci-dessous, vous comprendrez les concepts de Background:

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

Gul Md Ershad
la source
3

J'ai trouvé ceci ( WPF Multithreading: Utilisation de BackgroundWorker et rapport de la progression à l'interface utilisateur. Lien ) pour contenir le reste des détails qui manquent dans la réponse de @ Andrew.

La seule chose que j'ai trouvée très utile était que le thread de travail ne pouvait pas accéder aux contrôles de MainWindow (dans sa propre méthode), mais lors de l'utilisation d'un délégué dans le gestionnaire d'événements de la fenêtre principale, c'était possible.

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;
};
lko
la source