【问题标题】:C#/WinForms: ShowDialog and subsequent Show on FormC#/WinForms:ShowDialog 和随后的 Show on Form
【发布时间】:2011-07-04 11:46:59
【问题描述】:

由于我认为与此处无关的原因,我有一个或多个线程与单个实例 UI(表单)通信。

在工作线程中,我需要报告进度或输入数据或简单的选择。所有这些都来自用户与 UI 的交互,当然,对于 M$ .NET,所有 UI 都在主线程中运行。

显然,我需要处理 UI(主)线程和工作线程之间的线程同步。我通过正确验证InvokeRequired 和公司来做到这一点。

InvokeRequiredIsHandleCreatedIsDisposed 等有很多帖子和文章讨论不连贯和微妙之处,所以我不会谈论它。

我只想说,我的 UI 只是一个表单,应该显示为 modalmodeless 表单,具体取决于调用者的意愿。

一个可以UI.Warn( "Warning!" ),而另一个可以UI.Question( "Make a choice:", options... )

现在考虑以下 M$DN 文档的摘录:

Form.ShowDialog Method:

与非模态表单不同,当用户单击关闭表单按钮时,.NET Framework 不会调用 Close 方法...

我从来没有关注过显示为 modal 的表单,但是他们的实现者说它不会被销毁,在关闭(隐藏)后可能会处于不可用状态。

但确实如此!

当表单从ShowDialog( ) 返回时,它的Handle 只是被丢弃,因为相信当再次需要它时,将调用ShowDialog( ) 并重新创建句柄。

我不知道为什么 M$ 的东西需要这样做,但我只是认为我可以让完全相同的表单完美地充当 modalmodeless 没有问题。 M$DN 文档没有说它被禁止(或者我喝醉了找不到它)!

嗯,最后它是一种相对简单(和肮脏)的修复方法。

var r = ShowDialog( );

// Handle thrown away aftr "ShowDialog()" supposing the
// next one will recreate it.
if ( !this.IsHandleCreated )
{
    // Force "Handle" recreation here, while in the main thread,
    // before any "Show()" happens.
    CreateHandle( );
}

return r;

它有效,但我想知道它是否不应该是达到同一目的的任何体面的方式。 (也许在一些不携带任何限制祖先兼容性包的东西中进行编程,因为 .NET 仍然如此......)

【问题讨论】:

  • 当你说 M$ 时,我不能把你当回事。
  • 我猜他只是对MS有点生气-)
  • 问题是:我应该如何清洁?有没有合适的方法来做到这一点?

标签: c# multithreading forms dialog invoke


【解决方案1】:

你确定你没有这个倒退吗?我创建了一个简单的空白表单用作模式对话框,然后用一个简单的表单对其进行了测试,该表单只有一个显示对话框的按钮。

public partial class Form1 : Form
{
    private MyDialog theDialog;
    public Form1()
    {
        InitializeComponent();
        theDialog = new MyDialog();
    }

    private void button1_Click(object sender, EventArgs e)
    {
        theDialog.ShowDialog();
    }
}

我可以毫无问题地重复显示对话框。

现在,如果我调用theDialog.Show(),将其关闭,然后再次尝试显示,我会收到ObjectDisposedException

因此,文档是正确的:ShowDialog 不调用 Form.Close,而 Show 显然调用。

编辑:

Form.Close 的文档告诉您如果要防止表单被破坏,您必须做什么:

您可以阻止关闭表单 在运行时通过处理关闭 事件并设置 Cancel 属性 的 CancelEventArgs 作为 事件处理程序的参数。

有了这些信息和几分钟的思考,拥有一个可以显示为模态或非模态的表单是微不足道的:

public partial class Form1 : Form
{
    private MyDialog theDialog;
    public Form1()
    {
        InitializeComponent();
        theDialog = new MyDialog();
        theDialog.FormClosing += new FormClosingEventHandler(theDialog_FormClosing);
    }

    void theDialog_FormClosing(object sender, FormClosingEventArgs e)
    {
        e.Cancel = true;
        theDialog.Hide();
    }

    private void button1_Click(object sender, EventArgs e)
    {
        if (theDialog.Visible)
        {
            theDialog.BringToFront();
        }
        else
        {
            theDialog.ShowDialog();
        }
    }

    private void button2_Click(object sender, EventArgs e)
    {
        if (theDialog.Visible)
        {
            theDialog.BringToFront();
        }
        else
        {
            theDialog.Show();
        }
    }
}

【讨论】:

  • 好的。现在尝试“显示()”你的表单,“隐藏()” - 而不是“关闭()” - 并将其混合到“ShowDialog()”调用中。
  • 你找到我了。我几乎做对了,但没有意识到我应该(或可以)隐藏表单,即使“显示对话框”也是如此。我现在将分析多线程仍然会破坏我的生活,但测试程序确实如你所说,Jim。非常感谢。它变得非常干净。
  • 我希望我在一小时前注意到这一点:我几乎做对了,但没有意识到我应该(或可能)隐藏表单,即使ShowDialog'ing 它也是如此。 隐藏模式对话框感觉很奇怪。
猜你喜欢
  • 2012-11-15
  • 1970-01-01
  • 2012-12-07
  • 1970-01-01
  • 2023-03-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多