wpf
Thread-Affinität Zugriff auf Benutzeroberflächenelemente
Suche…
Zugriff auf ein Oberflächenelement innerhalb einer Aufgabe
Alle Elemente der Benutzeroberfläche, die erstellt wurden und sich im Haupt-Thread eines Programms befinden. Der Zugriff auf diese von einem anderen Thread aus ist in der .net Framework-Laufzeitumgebung verboten. Grundsätzlich liegt dies daran, dass alle Elemente der Benutzeroberfläche Thread-empfindliche Ressourcen sind und der Zugriff auf eine Ressource in einer Multithread-Umgebung Thread-sicher sein muss. Wenn dieser Cross-Thread-Objektzugriff zulässig ist, wird die Konsistenz in erster Linie beeinträchtigt.
Betrachten Sie dieses Szenario:
Wir haben eine Berechnung innerhalb einer Aufgabe. Aufgaben werden in einem anderen Thread als dem Hauptthread ausgeführt. Während der Berechnung müssen wir eine Fortschrittsleiste aktualisieren. Um dies zu tun:
//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);
Jedes Oberflächenelement verfügt über ein Dispatcher-Objekt, das von seinem DispatcherObject
Vorfahren (innerhalb des System.Windows.Threading
Namespace) stammt. Der Dispatcher führt den angegebenen Delegaten synchron mit der angegebenen Priorität in dem Thread aus, dem der Dispatcher zugeordnet ist. Da die Ausführung synchronisiert ist, sollte die aufrufende Task auf ihr Ergebnis warten. Dies gibt uns die Möglichkeit, int progress
auch innerhalb eines Dispatcher-Delegierten einzusetzen.
Wir möchten ein UI-Element asynchron aktualisieren und dann die Änderungen der invokeAction
Definition ändern:
//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);
Dieses Mal haben wir int progress
gepackt und als Parameter für Delegierte verwendet.