2012-05-25 2 views
2

Я асинхронно работает Task, что пожары событие, когда он завершил так:Создание управления WPF из отдельной нити

task.ContinueWith(() => { 
    if (MyEvent != null) 
     MyEvent(this, EventArgs.Empty); 
} 

обработчик событий, то необходимо создать экземпляр управления WPF. Но когда я пытаюсь сделать это, это вызывает исключение: The calling thread must be STA, because many UI components require this. Исключение происходит в конструкторе класса при вызове метода.

Насколько я знаю, обычно acessing МОФ управления из отдельных threades обрабатывается с помощью Dispatcher.Invoke и он всегда работал для меня, так что я пробовал:

Dispatcher.Invoke(new Action(() => 
{ 
    InitializeComponent(); 
})); 

Но в этом случае исключение держит происходит. Может ли кто-нибудь сказать, как создать экземпляр элемента управления WPF из отдельного потока? Или, может быть, это будет лучший подход для маршаллинга события завершения в основной поток пользовательского интерфейса, если да, как я могу это сделать?

Любая помощь приветствуется. Благодарю.

ответ

3

Вы должны использовать экземпляр диспетчера, связанный с потоком пользовательского интерфейса. Если вы пишете что-то вроде этого:

Dispatcher.Invoke(new Action(() => 
{ 
    InitializeComponent(); 
})); 

в теле задачи, вы используете диспетчер вызывающего потока, который может быть фоновый поток из пула.

В любом случае, с задачами вы не должны использовать диспетчер напрямую. Используйте соответствующий планировщик задач:

var ui = TaskScheduler.FromCurrentSynchronizationContext(); 
Task.Factory.ContinueWhenAll(tasks.ToArray(), 
    result => 
    { 
     // put you UI calls here 

    }, CancellationToken.None, TaskContinuationOptions.None, ui); 

где tasks является последовательность задач запущенную с планировщиком по умолчанию.

+0

Это похоже работать, спасибо! – Slippy

1

Я делал это в прошлом

Dispatcher.Invoke(DispatcherPriority.Normal, 
        new Action(
         delegate() 
         { 
          //access control created by main thread 
          textBlock.Text = msg; 
         } 
         )); 
+0

Я бы использовал 'DispatcherPriority.Render', так как мы создаем' Control'. – Guillaume

+0

Я смог добавить элементы управления к родителям таким образом, по крайней мере ... EX: panel.Children.Add (новый MyControl()) и т. Д. – TGH

+0

Спасибо, но 'Dispatcher.Priority' ничего не изменил в моем случае ( – Slippy

1

Calling InitializeComponent из конструктора на другой поток, кажется, глядя на неприятности. Объект еще не существует (мы находимся в конструкторе)

Маршаллинг его обратно в поток пользовательского интерфейса обычно выполняет трюк, но во время конструктора мне кажется плохой идеей.

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

Смежные вопросы