BackgroundWorker permet d’exécuter du code de manière synchrone sur un thread en tache de fond.
On créé donc un second thread pour exécuter du code afin de ne pas bloquer le thread principal.
Approche différente de async, qui ne créé pas de nouveau thread mais met en pause et en mémoire le code à exécuter de manière asynchrone et l'exécute par petit bout afin de ne pas bloquer le thread principal.
|
The async-based approach to asynchronous programming is better than BackgroundWorker for IO-bound operations because the code is simpler and you don't have to guard against race conditions.
In combination with Task.Run, async programming is better than BackgroundWorker for CPU-bound operations because async programming separates the coordination details of running your code from the work that Task.Run transfers to the threadpool.
https://msdn.microsoft.com/en-us/library/mt674882.aspx |
BackgroundWorker et Dispatcher
Le Dispatcher permet de modifier des éléments (graphiques) du thread principal (MainThread) depuis un autre thread (background thread).
|
Le Dispatcher n'est accessible que depuis la couche vue. |
|
var backgroundWorker = new BackgroundWorker();
backgroundWorker.DoWork += new DoWorkEventHandler(backgroundWorker_DoWork);
backgroundWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(backgroundWorker_RunWorkerCompleted);
// Lance le thread en tâche de fond
backgroundWorker.RunWorkerAsync();
// Méthode qui contient le code a éxécuter dans un thread secondaire
void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
// le Dispatcher permet de modifier des éléments graphiques
// depuis un thread autre que le thread graphique.
Dispatcher.Invoke(DispatcherPriority.Normal, new Action<TypeArgument1, TypeArgument2>(méthode, argument1, argument2);
// Avec un paramètre de retour
bool b = (bool)System.Windows.Application.Current.Dispatcher.Invoke(DispatcherPriority.Normal, new Func<bool>(MaMethode));
// dans le cas ou le BackgroundWorker serait static
// il faut appeler le Dispatcher d'un objet non-static,
// ici le Dispatcher du formulaire.
mainWindow.Dispatcher.Invoke(DispatcherPriority.Normal, new Action(() =>
{
mainWindow.LoadGantt(schedule);
}));
}
// Méthode appelée lorsque le work a été réalisé
void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
// si une Exception s'est produit durant le DoWork,
// alors elle sera stockée dans e.Error
if (e.Error != null)
{
MessageBox.Show(e.Error.Message, "Error", MessageBoxButton.OK,
MessageBoxImage.Error, MessageBoxResult.OK, MessageBoxOptions.None);
}
else
{
// n'acceder à e.Result que si e.Error est null
}
}
|
|
An object reference is required for the non-static field, method, or property.
Utiliser System.Windows.Application.Current.Dispatcher.Invoke |
Passer des arguments au BackgroundWorker
|
var backgroundWorker = new BackgroundWorker();
backgroundWorker.DoWork += backgroundWorker_DoWork;
var monArgument = 10;
// Lance le thread en tâche de fond
backgroundWorker.RunWorkerAsync(monArgument); // un seul argument de type object peut être passé
void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
// récupération de l'argument
int argument = (int)e.Argument;
}
// un autre moyen de passer des arguments
backgroundWorker.DoWork += (obj, e) => WorkerDoWork(arg1, arg2);
void WorkerDoWork(string arg1, int arg2) { }
|
Callback
|
public delegate void Callback();
public void MaMethode()
{
// test si le thread en cours peut accéder aux ressources de l'objet courant
if (this.Dispatcher.CheckAccess())
{ // modification des ressources de l'objet courant }
else
{ // relancer la méthode avec le bon thread
var myCallback = new Callback(MaMethode);
this.Dispatcher.Invoke(DispatcherPriority.Normal, myCallback);
}
}
|