2016-03-27 1 views
0

Lorsque j'ai besoin d'effectuer une action longue, je l'appelle dans un BackgroundWorker comme celui-ci, afin de ne pas geler l'interface utilisateur;Utilisation de l'arrière-plan et mise à jour de l'interface utilisateur

BackgroundWorker bgWorker = new BackgroundWorker(); 

bgWorker.DoWork += (s, e) => { 
    //Do something long lasting 
    for(int i = 0; i < x; i++){ 

     //Performing action i of x 

     //While doing so update the progressbar 
     prgBar.Dispatcher.Invoke(() =>{ 
      prgBar.Value += ((i/x) * 100.0); 
     }); 

    } 
}; 

bgWorker.RunWorkerCompleted += (s, e) => { 
    //Finish up things 
}; 
bgWorker.RunWorkerAsync(); 

Est-ce «le chemin à parcourir» pour mettre à jour l'interface utilisateur ou est-ce «pas fait»? La même question s'applique à BackgroundWorker (peut-être commencer un nouveau thread au lieu d'un BackgroundWorker?)

+1

Je voulais juste noter que si vous souhaitez mettre à jour l'interface utilisateur sans gel à cause d'une tâche de fond, de la manière habituelle est de nos jours l'async-await méthode. –

Répondre

3

Si vous devez mettre à jour certains composants de l'interface utilisateur à partir d'un thread d'arrière-plan, vous devez utiliser Dispatcher pour rassembler l'appel au thread principal. Cela étant dit, vous semblez essayer de mettre à jour certaines barres de progression. La classe BackgroundWorker fournit déjà un mécanisme pour cela. Ainsi, vous pouvez simplement avoir un contrôle ProgressBar sur votre formulaire, puis:

var bgWorker = new BackgroundWorker(); 

// Specify that this worker supports progress 
bgWorker.WorkerReportsProgress = true; 

bgWorker.OnProgressChanged += e => 
{ 
    // This is called on the main thread. It safe to update your UI components here 
    myProgressBar.Value = e.ProgressPercentage; 
}; 

bgWorker.DoWork += (s, e) => 
{ 
    // Do something long lasting 
    for(int i = 0; i < x; i++) { 
     //Performing action i of x 

     // While doing so notify the subscribers of the progress event 
     var progress = (int)((i/x) * 100.0); 
     bgWorker.ReportProgress(progress); 
    } 
}; 

bgWorker.RunWorkerCompleted += (s, e) => 
{ 
    //Finish up things 
}; 

bgWorker.RunWorkerAsync(); 
1

Non, ce n'est pas le cas. Le principal problème est votre barre de progression - elle est mise en cache sur le thread de travail en arrière-plan, pas sur le thread de l'interface utilisateur. Il n'est jamais vraiment accroché à quoi que ce soit - où est-il montré?

La bonne façon est d'avoir un formulaire qui contient la barre de progression, et de l'ouvrir dans le fil de l'interface utilisateur (ou de commencer à le faire) AVANT de démarrer le fondeur, puis le masquer.

La logique de mise à jour avec Dispatcher est "correcte" bien qu'elle frappe pour l'instant une barre de progression initialisée de manière incorrecte. Mais l'invocation est ce que vous devez faire.