Pull to refresh

Многопоточность в WPF

Переходя с WinForms на WPF сталкнулся с проблемой, что привычный способ доступа к визуальным компонентам из потока отличного от их создавшего немного отличается. Это выразилось в первую очерь в том, что у WPF формы нет свойства InvokeRequired.
Поэтому давайте посмотрим простой пример выполнения длительной операции в отдельном потоке.
В качестве длительной операции возьмем вот такой метод:
private int LongOperation()
{
for (int i = 0; i < 100; i++)
{
// Имитация полезной работы
Thread.Sleep(100);
// Сообщаем в визуальную часть, что часть работы выполнена
SetProgressBarValue(i + 1);
}
return 0;
}

А в качестве тестовой формы, вот такую:
image
Обработчик кнопки:
private void startButton_Click(object sender, RoutedEventArgs e)
{
Func<int> operation = LongOperation;
operation.BeginInvoke(null, null);
}


Итак, реализация метода SetProgressBarValue «в лоб»:
private void SetProgressBarValue(int newValue)
{
workProgress.Value = newValue;
}

Что логично приводит к ошибке InvalidOperationException.
Как было уже сказано, InvokeRequired отсутствует :(
Но не все так плохо как могло бы быть, в WPF для решения этой проблемы используется замечательный класс Dispatcher. Который позволяет не только получить ссылку на поток создававший визуальную часть приложения, но и запустить в этом потоке заданный метод. Таким образом метод SetProgressBarValue может быть переписан следующим образом:
// Делегат для перевызова метода SetProgressBarValue через диспетчер
private delegate void SetProgressBarValueHandler(int newValue);

private void SetProgressBarValue(int newValue)
{
// Проверяем совпадает ли поток диспетчера с потоком вызвавшим метод
if (Dispatcher.Thread == Thread.CurrentThread)
{
// Все замечательно :) меняем значение прогресбара
workProgress.Value = newValue;
}
else
{
// Нет :( все плохо :( перезапускаем методв в потоке диспетчера
Dispatcher.Invoke(new SetProgressBarValueHandler(SetProgressBarValue), new object[] { newValue });
}
}


Вуаля :) Все заработало

Полезные ссылки:
Для работы приложения необходим Microsoft .NET Framework 3.5 Service Pack 1
В проекте использовалась тема с codeplex
Исходники расмотренного примера можно скачать от сюда
Tags:
Hubs:
You can’t comment this publication because its author is not yet a full member of the community. You will be able to contact the author only after he or she has been invited by someone in the community. Until then, author’s username will be hidden by an alias.