Обходной путь «вызывающий поток должен быть STA»
Я знаю, что есть несколько ответов на эту тему по SO, но я не могу получить ни одно из решений, работающих на меня. Я пытаюсь открыть новое окно из ICommand, запущенного из таблицы данных. Оба приведенных ниже дают вышеупомянутую ошибкуwhen the new window is instantiated (внутри & quot; нового MessageWindowP & quot;):
Using TPL/FromCurrentSynchronizationContext Update: works
<code>public class ChatUserCommand : ICommand { public void Execute(object sender) { if (sender is UserC) { var user = (UserC)sender; var scheduler = TaskScheduler.FromCurrentSynchronizationContext(); Task.Factory.StartNew(new Action<object>(CreateMessageWindow), user,CancellationToken.None, TaskCreationOptions.None,scheduler); } } private void CreateMessageWindow(object o) { var user = (UserC)o; var messageP = new MessageWindowP(); messageP.ViewModel.Participants.Add(user); messageP.View.Show(); } } </code>
Using ThreadStart: Update: not recommended, see Jon's answer
<code>public class ChatUserCommand : ICommand { public void Execute(object sender) { if (sender is UserC) { var user = (UserC)sender; var t = new ParameterizedThreadStart(CreateMessageWindow); var thread = new Thread(t); thread.SetApartmentState(ApartmentState.STA); thread.Start(sender); } } private void CreateMessageWindow(object o) { var user = (UserC)o; var messageP = new MessageWindowP(); messageP.ViewModel.Participants.Add(user); messageP.View.Show(); } } </code>
Спасибо
РЕДАКТИРОВАТЬ. Основываясь на полученных ответах, я хотел бы отметить, что я также пробовал BeginInvoke на текущем диспетчере, а также выполняю код в исходном методе (то есть, как код начинался). Увидеть ниже:
BeginInvoke Update: not recommended see Jon's answer
<code>public class ChatUserCommand : ICommand { public void Execute(object sender) { if (sender is UserC) { var user = (UserC)sender; Dispatcher.CurrentDispatcher.BeginInvoke(new Action<object>(CreateMessageWindow), sender); } } private void CreateMessageWindow(object o) { var user = (UserC)o; var messageP = new MessageWindowP(); messageP.ViewModel.Participants.Add(user); messageP.View.Show(); } } </code>
In same thread Update: works if you are on UI thread already
<code>public class ChatUserCommand : ICommand { public void Execute(object sender) { if (sender is UserC) { var user = (UserC)sender; var messageP = new MessageWindowP(); messageP.ViewModel.Participants.Add(user); messageP.View.Show(); } } } </code>
BeginInvoke, using reference to dispatcher of first/main window Update: works
<code> public void Execute(object sender) { if (sender is UserC) { var user = (UserC)sender; GeneralManager.MainDispatcher.BeginInvoke( DispatcherPriority.Normal, new Action(() => this.CreateMessageWindow(user))); } } </code>
где GeneralManager.MainDispatcher - это ссылка на Dispatcher первого окна, которое я создаю:
<code> [somewhere far far away] mainP = new MainP(); MainDispatcher = mainP.View.Dispatcher; </code>
Я в растерянности.