让主线程再次运行?

发布于 2024-12-05 21:25:42 字数 626 浏览 0 评论 0原文

嗨,

我有一个托管 WCF 服务(NamedPipes)的 winform 应用程序。当接到电话时,将触发一个事件,然后创建并打开一个表单。问题是

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。

BestRegards

Edit1:请不要我正在使用

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

Hi,

I have a winform application that is hosting a WCF Service(NamedPipes). When reciving a call a event will be triggered and then a form will be created and opened. The problem is that I get the followin exception

ActiveX control '8856f961-340a-11d0-a96b-00c04fd705a2' cannot be instantiated because the current thread is not in a single-threaded apartment.

When creating a System.Windows.Forms.WebBrowser in the winforms InitializeComponent method?

I Supose that another thread is running the even(working thread), how can I get the main thread to run the event?

I do not have any winform open at the time so I can´t use InvokeRequired.

BestRegards

Edit1 : Pleas not that I am using

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

━╋う一瞬間旳綻放 2024-12-12 21:25:42

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

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

您还会遇到其他实际问题,您不能在没有用户参与的情况下弹出一个窗口。典型的事故是用户在没有看到它的情况下意外关闭它,或者窗口消失在用户正在使用的窗口后面。如果您已有用户界面,请务必使用 Control.BeginInvoke() 让主线程显示窗口。考虑使用 NotifyIcon 进行软触摸,在托盘通知区域中显示气球以提醒用户。

These kind of calls are made on thread pool threads. They are not suitable to display any UI. You'll need to create your own thread of the right flavor:

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

There are other practical problems you'll be battling with this, you can't just pop up a window without the user participating. Typical mishaps are the user accidentally closing it without even seeing it or the window disappearing behind the window that the user is working with. If you already have a user interface then be sure to use Control.BeginInvoke() to let the main thread display the window. Consider the soft touch with a NotifyIcon, displaying a balloon in the tray notification area to alert the user.

恋竹姑娘 2024-12-12 21:25:42

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

要让代码在主 UI 线程上执行,请使用 Control.Invoke 方法。它将把委托的执行编组到托管目标 ControlForm 的线程上。

如果您没有立即可用的 ControlForm 引用,那么您需要创建一个。您可能还必须创建一个运行消息循环的线程。这可以通过 Application.Run 来完成。创建一个可用于调用 Invoke 的隐藏 Form 非常简单。

它可能是这样的。

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(/* ... */);
}

That WCF call is most likely coming in on a thread other than the main UI thread. All UI controls including ActiveX ones must be created and accessed from the UI thread and only the UI thread. The error you are getting is indicating that the creating thread is not even in a Single Thread Apartment (STA) which is also a requirement.

To get the code executing on the main UI thread use the Control.Invoke method. It will marshal the execution of a delegate onto the thread hosting the target Control or Form.

If you do not have a reference to a Control or Form immediately available then you will need to create one. You may have to create a thread that runs a message loop as well. This can be done with Application.Run. It is simple enough to create a hidden Form that could be used to call Invoke.

Here is what it might look like.

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(/* ... */);
}
倾城花音 2024-12-12 21:25:42

我的解决方案是在启动时创建一个虚拟 winform,当我需要主 UI 线程时,我将在此虚拟表单上使用 invoke。

它将使用更多资源,但我没有看到更简单的方法。

My solution is to create a dummy winform on startup and when I need the main UI thread I will use invoke on this dummyform.

It will use some more resourse but I dont see a simpler way of doing it.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文