wpf
Affinité des threads Accès aux éléments de l'interface utilisateur
Recherche…
Accès à un élément d'interface utilisateur à partir d'une tâche
Tous les éléments d'interface utilisateur créés et résident dans le thread principal d'un programme. L'accès à ces derniers à partir d'un autre thread est interdit par le runtime du framework .net. Fondamentalement, c'est parce que tous les éléments d'interface utilisateur sont des ressources sensibles au thread et que l'accès à une ressource dans un environnement multithread nécessite d'être thread-safe. Si l'accès à cet objet est autorisé, la cohérence sera affectée en premier lieu.
Considérez ce scénario:
Nous avons un calcul dans une tâche. Les tâches sont exécutées dans un autre thread que le thread principal. Pendant que le calcul se poursuit, nous devons mettre à jour une barre de progression. Pour faire ça:
//Prepare the action
Action taskAction = new Action( () => {
int progress = 0;
Action invokeAction = new Action( () => { progressBar.Value = progress; });
while (progress <= 100) {
progress = CalculateSomething();
progressBar.Dispatcher.Invoke( invokeAction );
}
} );
//After .net 4.5
Task.Run( taskAction );
//Before .net 4.5
Task.Factory.StartNew( taskAction ,
CancellationToken.None,
TaskCreationOptions.DenyChildAttach,
TaskScheduler.Default);
Chaque élément d'interface utilisateur possède un objet Dispatcher provenant de son ancêtre DispatcherObject
(dans l'espace de noms System.Windows.Threading
). Dispatcher exécute le délégué spécifié de manière synchrone à la priorité spécifiée sur le thread auquel le Dispatcher est associé. Puisque l'exécution est synchronisée, la tâche de l'appelant doit attendre son résultat. Cela nous donne la possibilité d'utiliser int progress
également à l'intérieur d'un délégué répartiteur.
Nous souhaitons peut-être mettre à jour un élément d'interface utilisateur de manière asynchrone, puis invokeAction
modifications de définition d' invokeAction
:
//Prepare the action
Action taskAction = new Action( () => {
int progress = 0;
Action<int> invokeAction = new Action<int>( (i) => { progressBar.Value = i; } )
while (progress <= 100) {
progress = CalculateSomething();
progressBar.Dispatcher.BeginInvoke(
invokeAction,
progress );
}
} );
//After .net 4.5
Task.Run( taskAction );
//Before .net 4.5
Task.Factory.StartNew( taskAction ,
CancellationToken.None,
TaskCreationOptions.DenyChildAttach,
TaskScheduler.Default);
Cette fois, nous avons emballé le int progress
et l'avons utilisé comme paramètre pour délégué.