2016-06-06 2 views
1

это мой первый пост, так что простите меня, если я сделаю ошибки и ошибки.WPF - попытка открыть новое окно в задаче, но получить «вызывающий поток должен быть исключением STA»

У меня есть задача, которая возвращает строку. В рамках этой задачи я хочу открыть новое окно, в которое пользователь вводит код. После ввода кода и закрытия окна задача вернет код.

Мой код выглядит следующим образом:

public Task<string> GetLoginCode() 
     { 

      return Task.Run(() => 
      { 
       CodeRequestView view = new CodeRequestView(); 
       CodeRequestViewModel viewModel = new CodeRequestViewModel(); 
       view.ShowDialog(); 
       return viewModel.Code; 
      }); 

     } 

Проблема у меня, когда я бегу мой проект Im получая «Вызывающий поток должен быть STA, так как многие компоненты пользовательского интерфейса требуют этого.» исключение в конструкторе файла CodeRequestView.xmal.cs.

Некоторая помощь в том, как разрешить это было бы весьма полезно. Спасибо!

+0

Возможный дубликат [Вызывающий поток должен быть STA, так как многие компоненты пользовательского интерфейса требуют этого в WPF] (http://stackoverflow.com/questions/4183622/the-calling-thread-must-be-sta -because-many-ui-components-require-this-in-wpf) –

ответ

2

Как вы звоните UI Материал из не-UI-нити, вы можете использовать поток пользовательского интерфейса, например Dispatcher.

public Task<string> GetLoginCode() 
      { 

       return Task.Run(() => 
       { 
        CodeRequestViewModel viewModel = new CodeRequestViewModel(); 
        Application.Current.Dispatcher.Invoke(delegate 
        { 
         CodeRequestView view = new CodeRequestView(); 
         view.ShowDialog(); 
        }); 
        return viewModel.Code; 
       }); 
      } 
0

Окна и элементы управления WPF необходимо запускать на резьбе STA для своего apartment state. Task.Run() использует threadpool, которые определены как MTA, и им не разрешено создавать объекты подкласса Window, которые должны быть в потоке STA.

Вам необходимо вручную создать новый поток и установить его состояние квартиры в STA, прежде чем использовать его для создания новых объектов окна. Поскольку вы не показывали полные коды, так что я понятия не имею, почему именно ему нужно вернуть объект Task<string> вместо объекта string. Если вы хотите, чтобы это выполнялось асинхронно (ожидаемо), ваша исходная реализация с использованием Task.Run() уже запускает ее в другом потоке (из потока) и сразу же возвращается к вызывающему.

Во всяком случае, это пример:

public string GetLoginCode() 
{ 
    string retVal; 
    Thread viewThread = new Thread(() => 
    { 
     CodeRequestView view = new CodeRequestView(); 
     CodeRequestViewModel viewModel = new CodeRequestViewModel(); 
     view.ShowDialog(); 
     retVal = viewModel.Code; 
     }); 
    } 
    viewThread.SetApartmentState(ApartmentState.STA); 
    viewThread.Start(); 

    return retVal; 
} 

Я никогда не пробовал это, хотя, так что я не уверен, если возвращаемое значение будет вызывать проблемы синхронизации или нет.

+1

Возможно, вы захотите упомянуть OP, что наличие двух потоков STA, хотя и технически возможно, возможно, не рекомендуется для приложений с графическим интерфейсом. Нужно спросить, зачем нужно в первую очередь? _ – MickyD

+0

Я согласен с тем, что многие люди склонны создавать новые потоки (или из threadpool), когда это возможно, и это заставляет их чувствовать, что их приложение более отзывчивое. В большинстве случаев улучшение очень незначительно, но это дает им 10% проблемы, возникающей из-за нескольких потоков. OP действительно нуждается в том, чтобы спросить себя, почему это необходимо. Помните, что самое элегантное решение - это простое. – Jai

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