Вы не можете взаимодействовать с пользовательским интерфейсом ни в одном потоке, кроме потока пользовательского интерфейса, но вы можете использовать объект диспетчера пользовательского интерфейса для выполнения обратного вызова внутри потока пользовательского интерфейса:
System.Windows.Application.Current.Dispatcher.Invoke(new System.Action(() => { /* your UI code here */ }));
Более "чистый"способ получения диспетчера заключается в передаче его из объекта пользовательского интерфейса в поток / класс, который порождает поток, при его создании.
Редактировать:
Iрекомендую решение HCL по моему.Однако в комментариях вы спросили, как заставить это работать без дублирования этого большого неприятного блока кода:
В вашем конструкторе возьмите ссылку на объект Dispatcher
и сохраните его в своем классе.
Затем создайте метод, подобный этому:
private void RunOnUIThread(Action action)
{
this.dispatcher.Invoke(action);
}
И назовите его так:
RunOnUIThread(() => { /* UI code */ });
Вы можете обернуть большие блоки кода следующим образом:
RunOnUIThread(() =>
{
Console.WriteLine("One statement");
Console.WriteLine("Another statement");
});
Если вы попытаетесь перенести слишком много этого кода обратно в пользовательский интерфейс, он будет ничем не отличается от того, если вы выполнили весь код в потоке пользовательского интерфейса, и все равно будет зависать в пользовательском интерфейсе.
Однако предложение HCL о заполнении пользовательской древовидной структуры вместо того, чтобы этот код знал что-либо об элементах управления пользовательского интерфейса, гораздо лучше:)