Modifier les contrôles WPF à partir d’un thread non principal à l’aide de Dispatcher.Invoke

J’ai récemment commencé à programmer dans WPF et j’ai rencontré le problème suivant. Je ne comprends pas comment utiliser la méthode Dispatcher.Invoke() . J’ai de l’expérience dans le threading et j’ai fait quelques programmes Windows Forms simples où je viens d’utiliser le

 Control.CheckForIllegalCrossThreadCalls = false; 

Oui, je sais que c’est plutôt boiteux mais ce sont des applications de surveillance simples.

Le fait est que maintenant je fais une application WPF qui récupère les données en arrière-plan, je commence un nouveau thread pour faire l’appel pour récupérer les données (à partir d’un serveur web), maintenant je veux les afficher sur mon formulaire WPF. La chose est, je ne peux pas définir aucun contrôle de ce fil. Pas même une étiquette ou quoi que ce soit. Comment cela peut-il être résolu?

Répondre aux commentaires:
@Jalfp:
J’utilise donc cette méthode Dispatcher dans la «nouvelle bande de roulement» lorsque je reçois les données? Ou devrais-je demander à un travailleur en arrière-plan de récupérer les données, de les placer dans un champ et de lancer un nouveau thread qui attend que ce champ soit rempli et d’appeler le répartiteur pour afficher les données récupérées dans les contrôles?

La première chose à faire est de comprendre que le Dispatcher n’est pas conçu pour exécuter de longues opérations de blocage (telles que la récupération de données à partir d’un serveur Web …). Vous pouvez utiliser le répartiteur lorsque vous souhaitez exécuter une opération qui sera exécutée sur le thread d’interface utilisateur (par exemple, la mise à jour de la valeur d’une barre de progression).

Ce que vous pouvez faire, c’est récupérer vos données dans une tâche en arrière-plan et utiliser la méthode ReportProgress pour propager les modifications dans le thread d’interface utilisateur.

Si vous avez vraiment besoin d’utiliser le Dispatcher directement, c’est assez simple:

 Application.Current.Dispatcher.BeginInvoke( DispatcherPriority.Background, new Action(() => this.progressBar.Value = 50)); 

japf a répondu correctement. Juste au cas où vous regardez des actions multi-lignes, vous pouvez écrire comme ci-dessous.

 Application.Current.Dispatcher.BeginInvoke( DispatcherPriority.Background, new Action(() => { this.progressBar.Value = 50; })); 

Informations pour les autres utilisateurs qui souhaitent connaître les performances:

Si votre code doit être écrit pour des performances élevées, vous pouvez d’abord vérifier si l’appel est requirejs à l’aide de l’indicateur CheckAccess.

 if(Application.Current.Dispatcher.CheckAccess()) { this.progressBar.Value = 50; } else { Application.Current.Dispatcher.BeginInvoke( DispatcherPriority.Background, new Action(() => { this.progressBar.Value = 50; })); } 

Notez que la méthode CheckAccess () est masquée dans Visual Studio 2015, il suffit de l’écrire sans attendre d’intellisense pour l’afficher. Notez que CheckAccess a une surcharge sur les performances (surcharge en quelques nanosecondes). Ce n’est que mieux si vous voulez économiser la microseconde requirejse pour effectuer l’invocation à tout prix. En outre, il y a toujours une option pour créer deux méthodes (on avec invoke, et d’autres sans) lorsque l’appel de la méthode est sûr si c’est dans UI Thread ou non. Ce n’est que le cas le plus rare où vous devriez regarder cet aspect du répartiteur.