从main打开窗口的WPF错误:调用线程必须是STA,因为许多UI组件都需要这个 [英] WPF Error opening window from main: The calling thread must be STA, because many UI components require this

查看:132
本文介绍了从main打开窗口的WPF错误:调用线程必须是STA,因为许多UI组件都需要这个的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我不是一个经验丰富的WPF人,但在过去使用后台线程对我来说效果很好,但在这个例子中我需要从我的MainWindow打开一个小窗口(CallBubble),我得到了各种各样的调用线程必须是STA,因为许多UI组件需要这个悲伤。窗口没有在主UI线程上创建和打开,因为它冻结了主窗口并且客户一直抱怨(在XP上它实际上使主窗口瘫痪),因此努力将它放在自己的线程上。



这就是我与背景工作者一起做的事情(只显示相关部分):

I'm not a seasoned WPF guy, but in the past using a background thread has worked just fine for me, but in this instance I need to open a little window (CallBubble) from my MainWindow, and I'm getting all kinds of "The calling thread must be STA, because many UI components require this" grief. The window is not being created and opened on the main UI thread because it freezes the main window and the customer has been complaining (on XP it actually cripples the main window), hence the effort to get it on its own thread.

This is how I was doing it with a background worker (just the relevant parts shown):

private void CaptureEvent(){

   ourBackgroundWorker.DoWork += OpenCallBubble;
   ourBackgroundWorker.RunWorkerCompleted += BubbleBackgroundWorkerCompleted;
   ourBackgroundWorker.RunWorkerAsync();

}

private void OpenCallBubble(object sender, DoWorkEventArgs e){
   
   CallBubble ourCallBubble = new CallBubble();
   
}



...我得到


...and I get the

"The calling thread must be STA, because many UI components require this"

错误,并且从它的构造函数开始。



如果任何人都可以修改上面的内容来工作一个后台工作者(我怀疑),或作为一个自定义线程,或实施STA反对它......我将不胜感激。请回复所有代码。



谢谢,



Barry

error on the creation of the CallBubble, and from its constructor.

If anyone can modify the above to work either as a background worker (which I doubt), or as a custom thread, or implementing STA against it...I would be much appreciated. Please reply though with ALL the code required.

Thanks,

Barry

推荐答案

这是真的。特别是,WPF应用程序UI线程本身需要STA。这很容易解决。对于主线程,这由应用于应用程序入口点的属性控制:

That's true. In particular, WPF application UI thread itself requires STA. This is easy to fix. For a main thread, this is controlled by the attribute applied to the application entry point:
[STAThread]
static void Main() {
    //...
}



这实际上是为初创公司设置线程公寓状态的唯一有效方法这个过程的线程,由于我在下面解释的原因。


您可能认为WPF应用程序中不存在这样的事情,但事实并非如此。这个代码只是由应用程序模板为您生成(您可以在构建时在项目下找到它,只需进行一些文本搜索),但在某些情况下,您必须手动编写这部分代码,以实现某些自定义行为。



现在,剩下的问题是为您在运行时创建的线程设置公寓状态,只有在某些人需要时才需要这样做线程使用的代码。这也不是问题。要理解的一件事是:线程无法通过此线程中运行的代码更改其公寓状态。您只能在其他线程中执行此操作,通常是创建和启动线程的代码,并且仅在启动它之前执行。这里:

http://msdn.microsoft。 com / en-us / library / system.threading.thread.setapartmentstate.aspx [ ^ ]。



(在某些问题上确实需要这个。一个这样的案例我记得是语音识别。语音识别类只需要STA,另一个 - 只有MTA。)



就是这样。



-SA


This is actually the only valid way to set a thread Apartment State for the start-up thread of the process, by the reason I explain below.

You may think that such thing does not exist in a WPF application, but that's not true. This code is simply generated for you by the application template (you can find it under your project when it is build, just do some text search), but in some cases you have to write this part of code manually, to achieve some customized behavior.

Now, the remaining problem is to set up the Apartment State for the thread you create during run time, which you need to do only if it is required by some code used by the thread. This is also not a problem. One thing to understand is: a thread cannot change its Apartment State by the code running in this thread. You can only do it in some other thread, usually the code where the thread is created and started, and only before starting it. Here:
http://msdn.microsoft.com/en-us/library/system.threading.thread.setapartmentstate.aspx[^].

(This is really needed in some question. One such case I remember is speech recognition. On of the speech recognizing classes requires only STA, another one — only MTA.)

That's it.

—SA


WPF主要基于 DependencyObject ,它只能托管在STA线程中。因此,在非STA线程中创建它们会导致异常。最重要的是,那些 BackgroundWorder 用于执行后台工作,如果你有一个长时间运行的进程,不会放弃该线程,请使用 BackgroundWorker的。他们不打算主持WPF控件。



因此,如果你想在UI线程之外创建一个新的 Window ,你需要创建一个new Thread (非线程)并使用 ApartmentState.STA调用 SetApartmentState 方法参数的值。



WPF is based heavily on DependencyObjects, which can only be hosted in a STA thread. So creating them in a non-STA thread results in exceptions. On top of that, those BackgroundWorders are there for doing background work, if you have a long running process that won't let go of the thread, use a BackgroundWorker. They're not intended to play host to WPF controls.

So, if you want to create a new Window outside of the UI thread, you need to create a new Thread (not thread) and call the SetApartmentState method with a ApartmentState.STA value for the parameter.

Thread otherWindowHostingThread = new Thread(new ThreadStart(OtherThreadStartPoint));
otherWindowHostingThread.SetApartmentState(ApartmentState.STA);
otherWindowHostingThread.Start();





您用作线程起点的方法需要调用新的 Window Show()方法,它还应告诉该线程的 Dispatcher 在方法完成执行之前启动。



我不是100%肯定这会有多好用,因为我只是在我第一次把WPF放在.net 3.5上时这样做了,我这样做的唯一原因是因为我在学习WPF。我还应该警告你,在 App 的UI线程之外创建的任何 Window 都不会被插入 App 窗口 s集合属性。



完整的解决方案可以在Sam Noble,Sam Bourton和Allen Jones的第8章C#2008中的WPF食谱,问题解决方案中找到。



The method you use as your thread starting point needs to call the new Window's Show() method, and it should also tell the that thread's Dispatcher to start before the method finishes executing.

I'm not 100% sure how well this will work out, because I've only done this when I was first leaning WPF on .net 3.5, and the only reason I did it was because I was learning WPF. I should also warn you that, any Windows created outside of the App's UI thread will not be inserted in the App's Windows collection property.

A full solution to this can be found in chapter 8 section 16 of "WPF Recipes in C# 2008, A Problem-Solution Approach" by Sam Noble, Sam Bourton, and Allen Jones.


// enable unit test to mock a dispatcher
var dispatcher = Dispatcher.CurrentDispatcher;
if (Application.Current != null)
{
    // use the application dispatcher if running from the software
    dispatcher = Application.Current.Dispatcher;
}

if (dispatcher != null)
{
    // delegate the operation to UI thread.
    dispatcher.Invoke(
        delegate
        {
            MessageBox.Show("Opeartion could not be completed. Please try again.","Error",MessageBoxButton.OK,MessageBoxImage.Error);
        });
}


这篇关于从main打开窗口的WPF错误:调用线程必须是STA,因为许多UI组件都需要这个的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆