2010-05-30 5 views
1

J'ai programmé C# pendant un certain temps (je suis une majeure en informatique) et je n'ai jamais eu à implémenter le threading.WPF BackgroundWorker Execution

Je suis en train de créer une application pour un client qui nécessite un threading pour une série d'opérations. En raison de la nature de l'accord client/fournisseur, je ne peux pas publier la source avec laquelle je travaille. Le code que j'ai posté est sous une forme générale. Assez l'idée de base de ce que je suis en train d'implémenter, en excluant la source spécifique au contenu.

La première Snippet démontre ma structure de base,

La classe Progress est une fenêtre de progression personnalisée qui apparaît comme une boîte de dialogue pour empêcher l'interaction de l'interface utilisateur de l'utilisateur. J'utilise actuellement le code pour compléter les appels de base de données basés sur une collection d'objets dans une autre zone du code de l'application. Par exemple, j'ai une collection d '"objets" d'une de mes classes personnalisées, que j'effectue ces appels de base de données pour ou au nom de. Ma configuration actuelle fonctionne très bien quand j'appelle le "GeneralizedFunction" une et une seule fois.

Ce que je dois faire est d'appeler cette fonction une fois pour chaque objet de la collection. J'essayais d'utiliser une boucle foreach pour parcourir la collection, puis j'ai essayé une boucle for.

Pour les deux boucles, le résultat était le même. L'opération Async fonctionne exactement comme souhaité pour le premier élément de la collection. Ceci, cependant, est le seul pour lequel il travaille. Pour chaque élément suivant, la boîte de progression (ma fenêtre personnalisée) s'affiche et se ferme immédiatement.

En termes d'appels de base de données, les appels pour le premier élément de la collection sont les seuls à réussir. Tous les autres ne sont pas tentés.

J'ai essayé tout ce que je sais et je ne sais pas faire, mais je n'arrive pas à le faire fonctionner.

Comment puis-je faire en sorte que cela fonctionne pour toute ma collection?

Toute aide est très appréciée.

Progress progress; 

BackgroundWorker worker; 

// Cancel the current process 
private void CancelProcess(object sender, EventArgs e) 
{ 
worker.CancelAsync(); 
} 

// The main process ... "Generalized" 
private void GeneralizedFunction() 
{ 
progress = new Progress(); 
progress.Cancel += CancelProcess; 
progress.Owner = this; 

Dispatcher pDispatcher = progress.Dispatcher; 

worker = new BackgroundWorker(); 
worker.WorkerSupportsCancellation = true; 

object[] workArgs = { arg1, arg2, arg3}; 

worker.DoWork += delegate(object s, DoWorkEventArgs args) 
{ 
    /* All main logic here 

    */ 

    foreach(Class ClassObject in ClassObjectCollection) 
    { 
    //Some more logic here 

    UpdateProgressDelegate update = new UpdateProgressDelegate(updateProgress); 

    pDispatcher.BeginInvoke(update, arg1,arg2,arg3); 
    Thread.Sleep(1000); 
    } 
}; 
worker.RunWorkerCompleted += delegate(object s, RunWorkerCompletedEventArgs args) 
{ 
    progress.Close(); 
}; 

worker.RunWorkerAsync(workArgs); 
progress.ShowDialog(); 
} 

public delegate void UpdateProgressDelegate(arg1,arg2,arg3); 

private void updateProgress(arg1,arg2,arg3) 
{ 
//Update progress 
} 
+0

Clarify please: La boucle 'foreach' dans votre exemple de code ci-dessus fonctionne comme prévu? Ou existe-t-il une boucle externe appelant 'GeneralizedFunction' à plusieurs reprises? –

+0

Fenêtre de progression WPF simple avec annulation http://blog.quantumbitdesigns.com/2008/07/22/simple-wpf-progress-window-with-cancellation/ – abmv

Répondre

1

OK, donc vous avez un processus d'arrière-plan en cours d'exécution dans le gestionnaire DoWork. Ce thread génère un certain nombre d'autres threads (avec BeginInvoke), puis dort 1 seconde. (pourquoi le sommeil (1000)?)

Il ne semble y avoir aucune tentative d'attendre les threads UpdateProgressDelegate pour terminer après la boucle for. Vous appelez donc progress.Close(); lorsque certains de ces pDispatchers sont toujours en cours d'exécution.

Je ne peux pas non plus voir de communication entre le Bgw et la boîte de dialogue.

La solution rapide ici serait de ne pas appeler BeginInvoke dans la boucle mais d'exécuter toute la logique dans 1 le thread bgw. Commencez par le faire fonctionner. Et un conseil: les vrais programmes ne dorment pas()

Et puis, si vous voulez générer plus de threads, vous devez implémenter une logique de rendez-vous. Avec une classe EventWaitHandle ou quelque chose.

Notez que cela devient beaucoup plus facile dans .NET 4 (avec Parallel.ForEach)

+0

Je pense que vous lisez mal, il y a '' new' dialogue de progression pour chaque 'BackgroundWorker', et chaque travailleur boucle sur tout avant qu'il ne termine son travail et ferme sa progression. –

+0

@Aviad, vous avez peut-être raison, mais vous voyez un BeginInvoke dans la boucle dans DoWork(). Mais le vrai problème peut être avec les trucs Db (non montré). –

0

Définissez un point d'arrêt sur progress.Close() pour voir s'il est appelé (faisant disparaître la fenêtre de progression). Vous devez probablement appeler DispatcherOperation.Wait() pour vous assurer que DoWork() ne quitte pas tant que tous les travaux ASYNC ne sont pas terminés. BeginInvoke() renvoie DispatcherOperation - vous devez l'utiliser pour rejoindre les threads et attendez qu'ils se terminent.

Vous devez probablement conserver une liste de toutes les opérations Dispather invoquées (pDispatcher.BeginInvoke (update, arg1, arg2, arg3)). Après la boucle foreach, vous attendez que chacun termine. Je suppose que le problème est que RunWorkerCompleted se déclenche puisque vous n'attendez pas que DispatchOperation se termine (fermant ainsi la fenêtre de progression).