2012-03-12 10 views
1

У меня есть один поток, который генерирует элементы GUI в wpf. Холст есть рисовать объекты (прямоугольники и так далее ...)Task.Factory и связь между потоками

Это МОФ нити называет другой поток давайте назвать это расчета нити. Этот поток вычисляет размер и положение и т. Д. Элементов, которые будут отображаться на холсте.

Я хочу, чтобы эти две части (GUI и calculatio) выполнялись в разных потоках. «Поток вычислений» основан на библиотеке без ссылок на функциональность wpf.

Теперь я хочу показать промежуточные данные потока вычислений, отображаемого потоком wpf. Я делаю это таким образом:

известково-нить пожары событие (DataReady), реализуемый МОФ-нить:

void MyRegStringObject_DataReady() 
{ 
    if (DebugMode) 
    MyDrawingBoard.DrawRegElements(); 
} 

Проблема теперь в том, что выдается ошибка: «вызывающий поток не может получить доступ к этому объекту, потому что ему принадлежит другой поток»

Есть несколько ответов на этот вопрос в stackoverflow, ссылающихся на эту ошибку, но ни один из них не может помочь в моем случае.

Функция DrawRegElements() хочет, чтобы очистить объект холста (между прочим):

curCanvas.Children.Clear(); 

В этом положении в коде выбрасывается ошибка. Похоже, что функция MyRegStringObject_DataReady, инициированная событием из потока calc, также выполняется потоком calc. Но в классе определяется, что на основе wpf-потока.

Как я могу решить эту проблему? Кто-нибудь есть идеи? Кстати: известково-нить не называется так:

CalcElements = Task.Factory.StartNew<bool>(MyRegStringObject.CalcRegElements); 

Когда поток завершается я определил:

CalcElements.ContinueWith((FinishCalcRegElements) => 
{ 
    MyDrawingBoard.DrawRegElements(); 
}, CancellationToken.None, TaskContinuationOptions.None, 
TaskScheduler.FromCurrentSynchronizationContext()); 

Нет проблем с этим. Everythins работает идеально. Функция, определенная в ContinueWith, кажется, была обработана wpf-нитью.

ответ

2

Сообщение об ошибке прямолинейно, вы пытаетесь получить доступ к элементу пользовательского интерфейса из теперь владеющего потока. Делегирование этой работы WPF Dispatcher, который связан с Main UI потоком, который будет размещать все сообщения от рабочего потока пользовательского интерфейса резьбы:

Application.Current.Dispatcher.BeginInvoke((ThreadStart)delegate 
    {    
     MyDrawingBoard.DrawRegElements(); 
    }); 

Чтобы быть уверенным, что вы используете правильный Dispatcher, связанную с потоком Main UI, вы можете передать его как параметр в код рабочего потока, так что просто передайте Dispatcher.Current из основного потока пользовательского интерфейса, иначе вызов Dispatcher.CurrentDispatcher в рабочем потоке инициализирует новый экземпляр, связанный с потоком рабочего вызова. Или просто используйте Application.Current.Dispatcher, который будет ссылаться на диспетчер потоков основного интерфейса.

PS:

Но это определенно в классе, что МОФ-нить на основе

Это ошибочное предположение, сами классы не связаны с какой-либо темой. Примеры экземпляров Concrtete. Таким образом, вы можете создавать классы, связанные с интерфейсом UI/non-UI, либо в пользовательском интерфейсе, либо в потоке рабочего потока.

Также важный момент, в котором произошла авария DataReady?

+0

, когда вы говорите 'Dispatcher.Current', вы имеете в виду [Dispatcher.CurrentDispatcher] (http://msdn.microsoft.com/en-us/library/system.windows.threading.dispatcher.currentdispatcher.aspx), правильно? Я предполагаю, что MyDrawingBoard - это какой-то элемент управления WPF, так что «MyDrawingBoard.Dispatcher.BeginInvoke» будет в порядке. – Clemens

+0

Право 'CurrentDispatcher', исправлено. Вы пробовали это? – sll

+0

@ sll Dispatcher.CurrentDispatcher.BeginInvoke действительно не работает, я не знаю, почему, но UI-поток получает событие, запущенное рабочим потоком, но DrawRegElements не вызывается. Он вызывается только в конце (когда рабочий поток завершен). – manton