Вызывающий поток должен быть STA, потому что многие компоненты пользовательского интерфейса требуют этого

Я использую http://www.codeproject.com/KB/IP/Facebook_API.aspx

Я пытаюсь вызвать XAML, созданный с использованием WPF. Но это дает мне ошибку:

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

Я не знаю что делать. Я пытаюсь сделать это:

FacebookApplication.FacebookFriendsList ffl = new FacebookFriendsList();

Но это дает мне эту ошибку.

Я добавил фоновый рабочий:

static BackgroundWorker bw = new BackgroundWorker();

static void Main(string[] args)
{
    bw.DoWork += bw_DoWork;
    bw.RunWorkerAsync("Message to worker");
    Console.ReadLine();
}

static void bw_DoWork(object sender, DoWorkEventArgs e)
{
    // This is called on the worker thread
    FacebookApplication.FacebookFriendsList ffl = new FacebookFriendsList();

    Console.WriteLine(e.Argument);        // Writes "Message to worker"

    // Perform time-consuming task...
}

11 ответов

Попробуйте вызвать ваш код у диспетчера:

Application.Current.Dispatcher.Invoke((Action)delegate{
      // your code
});

Если вы делаете вызов из основного потока, вы должны добавить атрибут STAThread в метод Main, как указано в предыдущем ответе.

Если вы используете отдельный поток, он должен находиться в STA (однопотоковой квартире), что не относится к фоновым рабочим потокам. Вы должны создать тему самостоятельно, например так:

Thread t = new Thread(ThreadProc);
t.SetApartmentState(ApartmentState.STA);

t.Start();

с ThreadProc, являющимся делегатом типа ThreadStart.

Вы также можете попробовать это

// create a thread  
Thread newWindowThread = new Thread(new ThreadStart(() =>  
{  
    // create and show the window
    FaxImageLoad obj = new FaxImageLoad(destination);  
    obj.Show();  

    // start the Dispatcher processing  
    System.Windows.Threading.Dispatcher.Run();  
}));  

// set the apartment state  
newWindowThread.SetApartmentState(ApartmentState.STA);  

// make the thread a background thread  
newWindowThread.IsBackground = true;  

// start the thread  
newWindowThread.Start();  

Я подозреваю, что вы получаете обратный вызов для компонента пользовательского интерфейса из фонового потока. Я рекомендую вам сделать этот вызов, используя BackgroundWorker, так как он поддерживает потоки пользовательского интерфейса.

Для BackgroundWorker основная программа должна быть помечена как [STAThread].

Просто отметьте вашу программу с [STAThread] атрибут и ошибка уходит! это магия:)

В моем случае я хотел запустить окно WPF из консольного приложения. Просто установите метод Main с помощью [STAThread] не сработало.

Комбинация ответов Тимора и Мохаммеда сработала для меня:

      private static void StaThreadWrapper(Action action)
{
    var t = new Thread(o =>
    {
        action();
        System.Windows.Threading.Dispatcher.Run();
    });
    t.SetApartmentState(ApartmentState.STA);
    t.Start();
}

Пример использования:

      StaThreadWrapper(() =>
{
    var mainWindow = new MainWindow();
    mainWindow.Show();
});

Если Application.Current имеет значение null, например, с помощью модульного теста, вы можете попробовать следующее:

       System.Windows.Threading.Dispatcher.CurrentDispatcher.Invoke( YOUR action )

Application.Current.Dispatcher.Invoke((Action) делегат { // поместить код здесь});

Для меня эта ошибка произошла из-за передачи нулевого параметра. Проверка значений переменных устранила мою проблему без необходимости изменения кода. Я использовал BackgroundWorker.

Другая ситуация, если вы можете встретиться, выбирая, какое окно создать и показать .
Не делайте выбор в App.xaml.cs App() или OnStartup(), вместо этого сделайте выбор в событии Startup.

      // App.xaml.cs
        private App()
        {
            Window window = CheckSession() ? new InstallWindow() : (Window)new LoginWindow();
            window.Show(); // bad 1
        }

        protected override void OnStartup(StartupEventArgs e)
        {
            Window window = CheckSession() ? new InstallWindow() : (Window)new LoginWindow();
            window.Show(); // bad 2

            base.OnStartup(e);
        }

Ниже должно быть хорошо

      // App.xaml.cs
        private App()
        {
            Startup += Application_Startup;
        }

        private void Application_Startup(object sender, StartupEventArgs e)
        {
            Window window = CheckSession() ? new InstallWindow() : (Window)new LoginWindow();
            window.Show();  // good
        }

Также не забудьте удалить StartupUri из App.xaml.

      <!--App.xaml-->
<Application StartupUri="MainWindow">
<!--remove StartupUri-->
</Application>

ИЛИ добавить событие здесь тоже ОК.

      <!--App.xaml-->
<Application Startup="Application_Startup">

</Application>
      // App.xaml.cs
        private App()
        {
            
        }

        private void Application_Startup(object sender, StartupEventArgs e)
        {
            Window window = CheckSession() ? new InstallWindow() : (Window)new LoginWindow();
            window.Show();  // good
        }

Если вы вызовете оператор нового окна в существующем потоке, он выдаст ошибку. Вместо этого создайте новый поток внутри основного потока и запишите оператор окна UI в новом дочернем потоке.

Другие вопросы по тегам