Поиск…


Доступ к элементу пользовательского интерфейса изнутри задачи

Все элементы пользовательского интерфейса создаются и находятся в основном потоке программы. Доступ к ним из другого потока запрещен средой выполнения .net. В основном это связано с тем, что все элементы пользовательского интерфейса являются ресурсами, зависящими от потока, и доступ к ресурсу в многопоточной среде требует поточного контроля. Если этот доступ к объекту с поперечной резьбой разрешен, то в первую очередь будет затронута последовательность.

Рассмотрим этот сценарий:

У нас есть расчет, происходящий внутри задачи. Задачи выполняются в другом потоке, кроме основного потока. Когда вычисление продолжается, нам необходимо обновить индикатор прогресса. Сделать это:

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

Каждый элемент пользовательского интерфейса имеет объект Dispatcher, который исходит от его предка DispatcherObject (внутри System.Windows.Threading имен System.Windows.Threading ). Диспетчер выполняет указанный делегат синхронно с указанным приоритетом в потоке, с которым связан диспетчер. Поскольку выполнение синхронизировано, задача вызывающего абонента должна ждать его результата. Это дает нам возможность использовать int progress также внутри делегата диспетчера.

Возможно, мы захотим обновить элемент пользовательского интерфейса асинхронно, а затем 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);

На этот раз мы собрали int progress и использовали его в качестве параметра для делегата.



Modified text is an extract of the original Stack Overflow Documentation
Лицензировано согласно CC BY-SA 3.0
Не связан с Stack Overflow