Windows.Forms,在非模态状态下显示一个禁用的窗体

4

我有些困难,在非模态状态下显示一个禁用的表单。以下是示例代码:

public partial class Form1 : Form
{
    // ....
    private void button1_Click(object sender, EventArgs e)
    {
        try
        {
            Form2 form = new Form2();
            form.Enabled = false;
            form.Show();    // works, but form has no owner
            // form.Show(this); // gives an System.InvalidOperationException
            // ...
            // ... my program here shows a message box, ask user for something
            // ... while 'form' is shown in the background 
            form.Close();
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.Message);
        }

    }
}

有没有想过为什么 Show()(无参数)可以工作,但是 Show(this) 会抛出异常?在我的场景中,form 必须知道它的所有者才能正确显示,所以我可以这样做:
            form.Enabled = false;
            form.Owner=this;
            form.Show();

但这真的是一个好的解决方案吗?

编辑:感谢快速回答。看起来我们确实在框架中发现了一个错误。尽管您提出了建议,但我认为我会坚持我的解决方案,因为在“显示”后禁用表单会给用户带来不良的可见效果。


我的集成开发环境(IDE)显示:“不能将未启用的窗体显示为模态对话框。在调用 Show 方法之前,请将窗体的 enabled 属性设置为 true。” - Chris Haas
@Chris:我认为使用“Show”会以非模态状态显示窗体,只有使用“ShowDialog”才会以模态状态显示窗体,那么问题出在哪里呢? - Doc Brown
我希望我能告诉你。错误信息听起来应该适用于像你说的ShowDialog。要么这是一个错误,要么存在一个错误,你的解决方法实际上正在利用它,因为据我所知,两种Show()方法应该完全相同并设置相同的属性。 - Chris Haas
1
微软将不会修复这个错误:http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=525755 - serhio
1
@serhio:+1 给你,因为你的评论很中肯。但这并不意味着我们对此感到满意!我喜欢它被标记为“已解决”,实际上是“不会修复”。何不直接写成“永久不会解决”呢?“不会修复”。 - Dave Markle
显示剩余3条评论
3个回答

4

这是一个经典的复制粘贴错误。看起来他们从ShowDialog()中复制了代码,将禁用的窗体显示为对话框确实是无效的操作。用户将会被卡住,不能再进行任何操作。但是他们忘记在Show()方法中删除测试代码。只需在Show()调用后禁用它即可。


我也是这么想的。由于修复此错误可能会更改现有程序的行为,我怀疑微软永远不会修复它。 - Doc Brown
MS Connect: https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=525755 - serhio
不用费心了,他们不再修复这种类型的错误了。总之,解决方法很简单。 - Hans Passant

3

来自微软参考源代码:

public void Show(IWin32Window owner)
{
    if (owner == this)
    {
        throw new InvalidOperationException(SR.GetString("OwnsSelfOrOwner", new object[] { "Show" }));
    }
    if (base.Visible)
    {
        throw new InvalidOperationException(SR.GetString("ShowDialogOnVisible", new object[] { "Show" }));
    }

    // Here!!!
    if (!base.Enabled)
    {
        throw new InvalidOperationException(SR.GetString("ShowDialogOnDisabled", new object[] { "Show" }));
    }

    if (!this.TopLevel)
    {
        throw new InvalidOperationException(SR.GetString("ShowDialogOnNonTopLevel", new object[] { "Show" }));
    }
    if (!SystemInformation.UserInteractive)
    {
        throw new InvalidOperationException(SR.GetString("CantShowModalOnNonInteractive"));
    }
    if (((owner != null) && ((((int) UnsafeNativeMethods.GetWindowLong(new HandleRef(owner, Control.GetSafeHandle(owner)), -20)) & 8) == 0)) && (owner is Control))
    {
        owner = ((Control) owner).TopLevelControlInternal;
    }

顺便提一下,有一个微软反馈报告了一个 bug。


好的,但这是.NET框架中的一个错误吗?看起来这个异常应该在ShowDialog中抛出,而不是在Show中。 - Doc Brown
是的,这可以被解释为一个错误。所以在 Show() 之后你需要禁用表单。 - serhio
感谢向微软提供错误报告! - Doc Brown

2

我只能想到两种方法,一种是调用Show(this),另一种是禁用它。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接