我必须调用()来显示来自线程的对话框或MessageBox

本文关键字:线程 对话框 MessageBox 显示 调用 | 更新日期: 2023-09-27 18:05:02

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

我一直在玩代码,只有当我传递一个IWin32Window到对话框时,似乎对Invoke是严格必要的。

我的问题有两个:

  1. 我必须调用调用?
  2. 如果我显示对话框或消息框没有Invoke,我有什么风险?

Thanks in advance

我必须调用()来显示来自线程的对话框或MessageBox

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

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

还有一个更大的问题,在线程上显示对话框是一个严重的可用性问题。当用户正在使用你的程序时,把一个窗口塞到用户的脸上是一个非常糟糕的主意。当她忙于点击和打字时,谁也不知道会发生什么。她不小心关闭了对话框,甚至没有看到这是一个真正的危险。别这么做。

如果您没有指定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;
    }
}

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