У меня есть метод, которые создают фоновый поток для создания некоторого действия. В этом фоновом потоке я создаю объект. Но этот объект при создании во времени выполнения дает мне исключение:
Вызывающим потоком должен быть STA, потому что много компонентов UI требуют этого.
Я знаю, что должен использовать Диспетчера для создания, отражают что-то к UI. Но в этом случае я просто создаю объект и не делаю iteract с UI. Это - мой код:
public void SomeMethod()
{
BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += new DoWorkEventHandler(Background_Method);
worker.RunWorkerAsync();
}
void Background_Method(object sender, DoWorkEventArgs e)
{
TreeView tv = new TreeView();
}
Как я могу создать объекты в фоновом потоке?
Я использую приложение WPF
TreeView
- это элемент управления пользовательского интерфейса. Вы можете создавать элементы пользовательского интерфейса и управлять ими только в потоке пользовательского интерфейса, поэтому то, что вы пытаетесь сделать, невозможно.
Что вы хотите сделать, так это проделать всю трудоемкую работу в фоновом потоке, а затем «перезвонить» потоку пользовательского интерфейса для управления пользовательским интерфейсом. На самом деле это довольно просто:
void Background_Method(object sender, DoWorkEventArgs e)
{
// ... time consuming stuff...
// call back to the window to do the UI-manipulation
this.BeginInvoke(new MethodInvoker(delegate {
TreeView tv = new TreeView();
// etc, manipulate
}));
}
Возможно, я ошибся в синтаксисе для BeginInvoke
(это не в моей голове), но все равно что ...
Чтобы ваш код просто работал, вы должны присоединиться к квартире STA COM
, позвонив по телефону Thread.SetApartmentState (ApartmentState.STA)
. Поскольку BackgroundWorker
, вероятно, использует какой-то общий пул потоков, присоединение к конкретному апартаменту может повлиять на других пользователей этого пула потоков или даже может завершиться ошибкой, если он уже был установлен, например, MTA
ранее. Даже если все сработает, ваш вновь созданный TreeView
будет заблокирован для этого рабочего потока. Вы не сможете использовать его в своем основном потоке пользовательского интерфейса.
Если вы немного подробнее объясните свои истинные намерения, вам наверняка помогут.
Попробуйте ввести код:
public void SomeMethod()
{
System.ComponentModel.BackgroundWorker myWorker = new System.ComponentModel.BackgroundWorker();
myWorker.DoWork += myWorker_DoWork;
myWorker.RunWorkerAsync();
}
private void myWorker_DoWork(object sender,
System.ComponentModel.DoWorkEventArgs e)
{
// Do time-consuming work here
}
См. Ответ на этот вопрос: Как запустить что-то в потоке STA?
Когда вы определяете свой поток, установите для параметра ApartmentState значение STA:
thread.SetApartmentState(ApartmentState.STA);
Это должно помочь !
Я решил свою проблему. Я просто использовал свойство e.Result метода RunWorkerCompleted. Я получаю данные в фоновом потоке, а затем использую эти данные, когда поток завершается. Спасибо всем за полезные методы. Особая благодарность Виру за рекомендацию по свойству e.Result
.
HTH:
void Background_Method(object sender, DoWorkEventArgs e)
{
// Time Consuming operations without using UI elements
// Result of timeconsuming operations
var result = new object();
App.Current.Dispatcher.Invoke(new Action<object>((res) =>
{
// Working with UI
TreeView tv = new TreeView();
}), result);
}
void Background_Method(object sender, DoWorkEventArgs e)
{
TreeView tv = new TreeView();
// Generate your TreeView here
UIDispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() =>
{
someContainer.Children.Add(tv);
};
}