Обходной путь «Вызывающий поток должен быть STA»

Я знаю, что есть несколько ответов на эту тему на SO, но я не могу получить ни одно из решений, работающих на меня. Я пытаюсь открыть новое окно из ICommand, запущенного из шаблона данных. Оба следующих варианта дают вышеупомянутую ошибку при создании экземпляра нового окна(в «новом MessageWindowP»):

Использование TPL/FromCurrentSynchronizationContextОбновление :работает

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();
    }
}

Использование ThreadStart:Обновление :не рекомендуется, см. ответ Джона

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();
    }
}

Спасибо

РЕДАКТИРОВАТЬ. Основываясь на ответах до сих пор, я хотел бы отметить, что я также пробовал BeginInvoke в текущем диспетчере, а также выполнял код в исходном методе (, так код запускался ).См. ниже:

BeginInvokeОбновление :не рекомендуется см. ответ Джона

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();
    }
}

В том же потокеОбновление :работает, если вы уже находитесь в потоке пользовательского интерфейса

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();    
        }
    }

}

BeginInvoke, используя ссылку на диспетчер первого /main windowОбновление :работает

 public void Execute(object sender)
   {
       if (sender is UserC)
       {
            var user = (UserC)sender;
                    GeneralManager.MainDispatcher.BeginInvoke(
                               DispatcherPriority.Normal,
                               new Action(() => this.CreateMessageWindow(user)));      
        }
    }

, где GeneralManager.MainDispatcher — это ссылка на Dispatcher первого окна, которое я создаю:

     [somewhere far far away]
        mainP = new MainP();
        MainDispatcher = mainP.View.Dispatcher;

Я в недоумении.

6
задан Daniel A. White 7 August 2014 в 12:54
поделиться