Szukaj…


Dostęp do elementu interfejsu użytkownika z poziomu zadania

Wszystkie elementy interfejsu użytkownika utworzone i znajdują się w głównym wątku programu. Dostęp do nich z innego wątku jest zabroniony przez środowisko uruchomieniowe .net. Zasadniczo dzieje się tak, ponieważ wszystkie elementy interfejsu użytkownika są zasobami wrażliwymi na wątki, a dostęp do zasobu w środowisku wielowątkowym wymaga bezpieczeństwa wątków. Jeśli dostęp do tego obiektu z wątkiem krzyżowym jest dozwolony, w pierwszej kolejności miałaby to wpływ na spójność.

Rozważ ten scenariusz:

Mamy obliczenia wykonywane w ramach zadania. Zadania są uruchamiane w innym wątku niż główny wątek. Podczas obliczeń musimy zaktualizować pasek postępu. Aby to zrobić:

//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);

Każdy element interfejsu użytkownika ma obiekt Dispatcher, który pochodzi od jego przodka DispatcherObject (w przestrzeni nazw System.Windows.Threading ). Program rozsyłający wykonuje określonego delegata synchronicznie z określonym priorytetem w wątku, z którym jest powiązany program rozsyłający. Ponieważ wykonanie jest zsynchronizowane, zadanie dzwoniącego powinno poczekać na jego wynik. Daje nam to możliwość wykorzystania int progress również wewnątrz delegata dyspozytora.

Możemy chcieć zaktualizować element interfejsu użytkownika asynchronicznie, a następnie invokeAction zmiany definicji 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);

Tym razem zapakowaliśmy int progress i wykorzystaliśmy go jako parametr dla delegata.



Modified text is an extract of the original Stack Overflow Documentation
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow