Вызывающий поток должен быть 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 в новом дочернем потоке.