Winforms 让主线程重新运行?

Winforms 让主线程重新运行?,winforms,multithreading,browser,Winforms,Multithreading,Browser,你好, 我有一个winform应用程序,它承载一个WCF服务(NamedPipes)。收到呼叫时,将触发一个事件,然后创建并打开一个表单。问题是我得到了以下例外 ActiveX control '8856f961-340a-11d0-a96b-00c04fd705a2' cannot be instantiated because the current thread is not in a single-threaded apartment. 在winforms InitializeComp

你好,

我有一个winform应用程序,它承载一个WCF服务(NamedPipes)。收到呼叫时,将触发一个事件,然后创建并打开一个表单。问题是我得到了以下例外

ActiveX control '8856f961-340a-11d0-a96b-00c04fd705a2' cannot be instantiated because the current thread is not in a single-threaded apartment.
在winforms InitializeComponent方法中创建System.Windows.Forms.WebBrowser时

如果另一个线程正在运行偶数(工作线程),如何让主线程运行事件

我当时没有打开任何winform,因此无法使用InvokeRequired

问候

Edit1:请不要说我在用

[STAThread]
public static void Main(string[] args)
{
Application.Run(_instance);
}

该WCF调用很可能是在主UI线程以外的线程上进行的。包括ActiveX控件在内的所有UI控件都必须从UI线程创建和访问,并且只能从UI线程访问。您得到的错误指示创建线程甚至不在单线程单元(STA)中,这也是一个要求

要获取在主UI线程上执行的代码,请使用
控件.Invoke
方法。它将委托的执行封送到承载目标
控件
表单
的线程上

如果没有立即可用的
控件
表单
引用,则需要创建一个。您可能还必须创建一个运行消息循环的线程。这可以通过
应用程序来完成。运行
。创建一个隐藏的
表单
非常简单,可以用来调用
Invoke

下面是它可能的样子

void SomeMethodExecutingOnThreadPool()
{
  var form = null;
  var mre = new ManualResetEvent(false);

  // Create the UI thread.
  new Thread(
    () =>
    {
      form = new Form();
      form.Load += 
        (sender, args) => 
        {
          mre.Set();
        }
      Application.Run(form);
    }).Start();

  // Wait for the UI thread to initialize.
  mre.WaitOne(); 

  // You can now call Invoke.
  form.Invoke(/* ... */);
}

这类调用是在线程池线程上进行的。它们不适合显示任何UI。您需要创建自己的具有正确风格的线程:

        var t = new Thread(() => {
            Application.Run(new Form1());
        });
        t.SetApartmentState(ApartmentState.STA);
        t.Start();

还有其他一些实际问题需要解决,你不能在没有用户参与的情况下弹出一个窗口。典型的事故是用户在没有看到它的情况下意外地关闭了它,或者窗口消失在用户正在使用的窗口后面。如果已经有用户界面,请确保使用Control.BeginInvoke()让主线程显示窗口。考虑与NotifyIcon的软接触,在托盘通知区域中显示一个气球来提醒用户。

< P>我的解决方案是在启动时创建一个虚拟Win窗体,当我需要主UI线程时,我将调用这个哑形。
它将使用更多的资源,但我看不到更简单的方法。

谢谢,但是主UI线程在哪里?我应该不使用那个线程吗?@SnowJim:和我一样,我怀疑Hans也认为不存在UI线程。很抱歉不清楚。应用程序将以[STAThread]public static void Main(字符串[]args)开始,然后是application.Run(_instance);。我想这意味着将创建一个UI线程(messagepump)。到目前为止,我的解决方案是在启动时创建一个dummyForm(从未显示),当需要UI线程时,将在此dummyForm上使用调用。坏/上帝?那是上帝。尽管我想知道_实例是如何创建的,以及如何确保它从不显示。使用它的BeginInvoke()方法。但是,如果我在当前线程池线程上创建一个窗体或控件,winform是否不会绑定到此线程?我听说创建表单/控件的线程必须是更新表单/控件的线程?或者主UI线程会在创建新表单/控件时介入并完成工作吗?你能举个小例子吗?吉姆:我更新了我的答案。您必须手动创建一个UI线程。谢谢,但如果应用程序正在主UI线程(使用application.Run)上运行其他部分,这将很奇怪。我是否可以在启动时简单地将当前UI线程存储在属性中,然后使用此线程触发事件?@SnowJim:等等……您已经有了一个主UI线程?我觉得情况并非如此。为什么不使用来自该UI线程的
表单
控件
引用?如果你没有打开一个,那么创建一个总是隐藏的虚拟
表单。你对dummyForm的建议是我目前的解决方案,但我不确定这是一条正确的道路。