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.



Modified text is an extract of the original Stack Overflow Documentation
Lizenziert unter CC BY-SA 3.0
Nicht angeschlossen an Stack Overflow