我必须 Invoke() 才能从线程显示对话框或 MessageBox 吗?

发布于 2024-11-28 09:17:40 字数 261 浏览 0 评论 0原文

我正在工作线程中执行代码。有时,我需要显示一个对话框或一条消息。

我一直在研究代码,当我将 IWin32Window 传递给对话框时,似乎只有严格需要 Invoke 。否则工作正常。

我的问题有两个:

  1. 我必须使用 Invoke 进行调用吗?
  2. 如果我在没有 Invoke 的情况下显示对话框或消息框,会有什么风险?

提前致谢

I'm executing a code in a worker thread. Sometimes, I need to show a dialog or a Message.

I have been playing with the code and only seems to be strictly necesary to Invoke when I pass a IWin32Window to the dialog. Otherwise works fine.

My questions are two:

  1. Must I call with an Invoke?
  2. What risks I have if I show the dialog or the messagebox without Invoke?

Thanks in advance

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

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

发布评论

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

评论(3

戏舞 2024-12-05 09:17:40

这是 Winforms 中的一个 bug。它在 Handle 属性 getter 中包含诊断代码,用于验证该属性是否在与创建该句柄的线程相同的线程中使用。虽然对于诊断线程错误非常有帮助,但这并不总是合适的。一种这样的情况是,Windows 实际上并不要求窗口的父窗口由同一线程拥有。

您可以通过 pinvoking SetParent() 或暂时禁用 Control.CheckForIllegalCrossThreadCalls 检查来解决此问题。或者使用 Control.Invoke(),这是最好的方法。不要通过不指定所有者来解决这个问题。由于缺少另一个窗口,对话框的所有者是桌面窗口。它与以桌面为所有者的其他窗口没有 Z 顺序关系。这将使对话框偶尔消失在另一个窗口后面,用户完全无法发现。

但还有一个更大的问题,在线程上显示对话框是一个令人讨厌的可用性问题。当用户使用你的程序时,将窗口推到用户的脸上是一个全面的坏主意。当她忙着点击和打字时,不知道会发生什么。她在没有看到的情况下意外关闭了对话框,这是一个真正的危险。不要这样做。

It is a bit of a bug in Winforms. It contains diagnostic code in the Handle property getter that verifies that the property is used in the same thread as the one that created the handle. While extremely helpful to diagnose threading bugs, that is not always appropriate. One such case is here, Windows doesn't actually require that the parent of a window is owned by the same thread.

You can work around it by pinvoking SetParent() or by temporarily disabling checking with Control.CheckForIllegalCrossThreadCalls. Or by using Control.Invoke(), the best way. Do not work around it by not specifying the owner. For lack of another window, the dialog's owner is the desktop window. It will have no Z-order relationship with the other windows that have the desktop as their owner. And that will make the dialog disappear behind another window occasionally, completely undiscoverable by the user.

There's a bigger problem though, displaying dialogs on threads is a nasty usability problem. Shoving a window into the user's face while she's working with your program is an all-around bad idea. There's no telling what will happen when she's busy clicking and typing. Her accidentally closing the dialog without even seeing it is a real danger. Don't do it.

只怪假的太真实 2024-12-05 09:17:40

如果您没有指定 MessageBox 的所有者,它将起作用,因为它不依赖于表单 UI 线程。
我认为如果您不知道显示为特定表单的对话框,则无需使用 Invoke 即可安全地调用它。

编辑:为了测试它,以下代码仅创建一个新线程并从中显示消息框,其中在 UI 线程中同时创建第二条消息并指定所有者为表单,这两条消息显示没有任何问题:

private void button1_Click(object sender, EventArgs e)
{
    new Thread(() =>
    {
        MessageBox.Show("Hello There!");
    }) { IsBackground = true }.Start();

    Thread.Sleep(1000);

    if (MessageBox.Show(this, "Hi", "Jalal", MessageBoxButtons.YesNo) == 
        System.Windows.Forms.DialogResult.Yes)
    {
        return;
    }
}

If you are not specifying the owner of the MessageBox it will work because it doesn't rely on the form UI thread.
I think it is safe to call it without using Invoke if you are not aware of showing as a dialog to specific form.

Edit: To test it, the following code just creating a new thread and show message box from it where at UI thread creating a second message at the same time with specifying the owner to be the form, both messages shows up without any problem:

private void button1_Click(object sender, EventArgs e)
{
    new Thread(() =>
    {
        MessageBox.Show("Hello There!");
    }) { IsBackground = true }.Start();

    Thread.Sleep(1000);

    if (MessageBox.Show(this, "Hi", "Jalal", MessageBoxButtons.YesNo) == 
        System.Windows.Forms.DialogResult.Yes)
    {
        return;
    }
}
π浅易 2024-12-05 09:17:40

当我需要与从另一个线程在主线程中创建的某些控件进行交互时,我使用BackgroundWorker。它有一个名为 OnProgressChange 的事件。所以maeby尝试在主线程中创建这个BackgroundWorker对象,并在DoWork方法中触发这个事件,然后附加到它的方法将在主线程中执行,这样你就可以访问所有控件。

When I need to interact with some controls, created in main thread from another thread I use BackgroundWorker. It has event called OnProgressChange. So maeby try create this BackgroundWorker object in main thread, and in DoWork method just fire this event, then method attached to it will be executed in main thread, so you have access to all controls.

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