C#/WinForms:ShowDialog和表单上的后续显示

C#/WinForms:ShowDialog和表单上的后续显示,c#,multithreading,forms,dialog,invoke,C#,Multithreading,Forms,Dialog,Invoke,由于我认为与此无关的原因,我有一个或多个线程与单个实例UI(表单)通信 在工作线程中,我需要报告进度、输入数据或简单的选择。所有这些都来自用户与UI的交互,当然,对于M$.NET,所有UI都在主线程中运行 显然,我需要处理UI(主)线程和工作线程之间的线程同步。我通过正确地验证invokererequired和company来实现这一点 在那里有大量的帖子和文章讨论了调用required、IsHandleCreated、IsDisposed等等中的不连贯和微妙之处,所以我不想谈论它 我只想说,我

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

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

显然,我需要处理UI(主)线程和工作线程之间的线程同步。我通过正确地验证
invokererequired
和company来实现这一点

在那里有大量的帖子和文章讨论了
调用required
IsHandleCreated
IsDisposed
等等中的不连贯和微妙之处,所以我不想谈论它

我只想说,我的UI,也就是一个表单,应该显示为模态或非模态表单,这取决于调用方的意愿

一个可以是
UI.Warn(“警告!”)
,而另一个可以是
UI.Question(“做出选择:”,选项…

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

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

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

但确实如此

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

我不知道为什么M$stuff需要这样做,但我只是认为我可以让完全相同的形式完美地作为模态或无模态而没有问题。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那样携带任何限制祖先兼容性的包袱…

您确定没有这方面的限制吗?我创建了一个简单的空白表单用作模式对话框,然后用一个简单表单测试它,该表单只有一个显示对话框的按钮

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

    private void button1_Click(object sender, EventArgs e)
    {
        theDialog.ShowDialog();
    }
}
我可以毫不费力地重复显示对话框

现在,如果我调用dialog.Show(),关闭它,然后再次尝试显示它,我会得到一个
ObjectDisposedException

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

编辑:

的文档告诉您,如果要防止表单被销毁,必须执行以下操作:

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

有了这些信息和几分钟的思考,就可以得到一个可以显示为模态或非模态的表单:

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

当你说M$的时候,我不能把你当回事。我猜他只是对MS-)有点生气。问题是:我该怎么把它弄干净?有什么好办法吗?好的。现在尝试“Show()”窗体,“Hide()”-而不是“Close()”-并将其混合到“ShowDialog()”调用中。明白了。我几乎做对了,但没有意识到我应该(或可能)隐藏表单,即使是在“展示”表单的时候。现在我将分析多线程仍然会破坏我的生活,但是一个测试程序真的像你说的那样工作,Jim。谢谢。它变得非常干净。我希望我在一小时前注意到这一点:我几乎做对了,但没有意识到我应该(或可能)隐藏表单,即使在
显示对话框时。隐藏模态对话框感觉很奇怪。