【问题标题】:Cross-thread exception when setting WinForms.Form owner - how to do it right?设置 WinForms.Form 所有者时的跨线程异常 - 如何正确执行?
【发布时间】:2011-07-13 12:29:05
【问题描述】:

我有一个主 UI 线程,它运行应用程序并创建主窗口窗体(我们称之为W)。我还有一个辅助线程,我启动它并创建一个对话框(我们称之为B)。

我想将对话框B 的所有者设置为主窗口WBs 所有者的设置发生在创建B 的线程上。基本上:

b.Owner = w;

但这会引发跨线程异常,告诉我我正在尝试从错误的线程访问 W 对象。

所以我尝试在主 UI 线程上执行代码,方法是在 W 上使用 Control.Invoke。但是,我得到了同样的错误,告诉我我正在尝试从错误的线程访问B

System.InvalidOperationException was unhandled by user code
  Message=Cross-thread operation not valid: Control 'B' accessed from a
  thread other than the thread it was created on.
  Source=System.Windows.Forms

我该怎么做才对?

【问题讨论】:

  • 不要在多个线程上使用表单。它会给你带来更多的麻烦。
  • 您是否阅读了这篇 SO 帖子:stackoverflow.com/questions/3046245/…?如果这对您没有帮助,您应该发布给出错误的代码。
  • 也许您可以告诉我们您希望利用哪些所有权功能(希望不是全部),我们可以建议实现类似效果的方法?
  • 感谢所有发帖的人;我知道我是在自找麻烦。我需要在主 UI 线程上运行一些遗留代码,并且我希望在发生这种情况时显示一个进度对话框;而且我不能让主 UI 线程处理进度对话框。所以我去找了一个由另一个线程 100% 管理的进度对话框。

标签: c# winforms invoke


【解决方案1】:

这是Winforms中的一个错误,Windows实际上支持使所有者成为在另一个线程上创建的窗口。有一种方法可以禁用该检查,这是您应该从不 做的事情。除非你必须这样做:

    private void button1_Click(object sender, EventArgs e) {
        var t = new Thread(() => {
            Control.CheckForIllegalCrossThreadCalls = false;
            var frm = new Form2();
            frm.Show(this);
            Control.CheckForIllegalCrossThreadCalls = true;
            Application.Run(frm);
        });
        t.SetApartmentState(ApartmentState.STA);
        t.Start();
    }

我确实知道这是否 100% 安全,可能会有 Winforms 交互搞砸了。你在这里未经测试的水域,有穿线鲨出没。

【讨论】:

  • 你的建议很有趣。就我而言,我可以确保显示对话框的代码不会干扰主 UI 线程。我试试看。
  • 您是否进一步了解了上述方法的安全性?我想这样做(让一个表单拥有一个绑定到不同线程的表单)但看到两个问题:(1)显示另一个拥有的表单将调用Owner.AddOwnedForm,这可能不是线程安全的;更好地在所有者表单的线程上执行操作; (2) 如果绑定到不同线程的两个表单尝试同时显示自己,一个可能会在另一个设置它为假的时间和它执行要求它为假的操作的时间之间设置CheckForIllegalCrossThreadCalls=true
  • 显然存在另一种解决方案,您将父级的.Handle 作为参数传递给线程的过程,并在过程create a NativeWindow 中从该句柄传递给.Show()。则不需要关闭CheckForIllegalCrossThreadCalls
【解决方案2】:

如果您实际上是在不同的线程上运行两个消息循环,那么就没有办法做您所追求的。如果你想让W 拥有B,你将不得不在主线程上创建B,并在第二个线程中创建InvokeB 的所有交互。

【讨论】:

    【解决方案3】:

    B需要在UI线程上创建。

    您仍然可以使用Control.Invoke 从辅助线程与B 交互。

    【讨论】:

    • 在我的情况下,它不会像我打算做的那样工作:如果主 UI 线程被阻止工作,我的 B 窗口将不会更新。
    猜你喜欢
    • 2023-02-23
    • 1970-01-01
    • 2011-10-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多