C#.NET MDI在以编程方式隐藏并再次显示最大化子表单时出现错误,并且在最大化时,无法更改子表单的图标

时间:2010-12-13 12:36:55

标签: c# .net mdi

基本上我在使用C#.NET MDI时遇到两个问题。您可以下载VS2010解决方案,它可以重现错误here

1)当以编程方式隐藏并再次显示最大化的子表单时,它不会再次正确最大化并且既不会最大化也不会处于正常状态。

childForm = new Form();
childForm.Text = "Child Form";
childForm.MdiParent = this;

...

private void showButton_Click(object sender, EventArgs e)
{
    childForm.Visible = true;
}

...

private void hideButton_Click(object sender, EventArgs e)
{
    childForm.Visible = false;
}

当儿童表单最大化,然后程序隐藏并再次显示时,它会变成这样(请注意菜单栏 - 显示子表单的控件框,但子表单没有最大化):

alt text

在这个阶段,儿童形式无法移动。但是,我找到了一个解决方法,只需显示并隐藏一个虚拟子表单,这会强制实际的子表单正确最大化。但这会使MDI区域闪烁。尝试了Invalidate,Refresh,Update方法,但它们没有帮助。也许有其他的解决方法可以克服这个错误,而不是让MDI区域与虚拟子表单闪烁?

private void workaround1Button_Click(object sender, EventArgs e)
{
    dummyForm.Visible = true;
    dummyForm.Visible = false;
}

2)当子表单最大化时,子表单的图标显示在菜单栏上。但是,如果您必须在子窗体最大化时更改图标,则菜单栏上的图标不会刷新(请参见上图)。我找到了一个解决方法,它基本上隐藏并显示菜单栏。图标会刷新,但它会使菜单栏下方的所有内容都闪烁。尝试了Invalidate,Refresh,Update方法,但它们没有帮助。有没有其他方法可以让菜单栏刷新子表单的图标?

private void workaround2Button_Click(object sender, EventArgs e)
{
    menuStrip.Visible = false;
    menuStrip.Visible = true;
}

另外我注意到当父窗体处于正常窗口状态模式(未最大化)并且您将窗体的宽度或高度更改为1像素时,子窗体变得最大化,因为菜单栏上的子窗体的图标得到了正确刷新,你不需要我上面描述的其他解决方法。如果我逐个更改表单的大小,请将表格闪烁1个像素,当父表单最大化时,我不能这样做。是否有任何方法可以调用重新调整/刷新功能,当您调整窗体大小时调用该功能并使子窗体正确地最大化并且菜单栏上的图标刷新?

5 个答案:

答案 0 :(得分:1)

您是否厌倦使用隐藏/显示而不是将可见设置为true / false?

尝试:

private void showButton_Click(object sender, EventArgs e)
{
    childForm.Show();
}

private void hideButton_Click(object sender, EventArgs e)
{
    childForm.Hide();
}

答案 1 :(得分:1)

内部MdiControlStrip类的实现存在一个错误,该控件在父窗口中显示图标和最小/最大/恢复字形。我还没有描述它,代码并不那么容易。该错误的一个典型副作用是字形加倍,你发现了一些其他的副作用。修复很简单,延迟创建子窗口,直到构造函数完成。像这样:

    public MainForm()
    {
        InitializeComponent();
    }
    protected override void OnLoad(EventArgs e) {
        childForm = new Form();
        childForm.Text = "Child Form";
        childForm.MdiParent = this;

        dummyForm = new Form();
        dummyForm.MdiParent = this;
        dummyForm.WindowState = FormWindowState.Maximized;
        base.OnLoad(e);
    }

答案 2 :(得分:1)

这个解决方法怎么样?

private void showButton_Click(object sender, EventArgs e)
{
    childForm.Visible = true;
    childForm.WindowState = (FormWindowState)childForm.Tag;
}

private void hideButton_Click(object sender, EventArgs e)
{
    childForm.Visible = false;
    childForm.Tag = childForm.WindowState;
    childForm.WindowState = FormWindowState.Normal;
}

<强>更新

我刚刚告诉你如何做到这一点。使用与上述相同的想法的更好的解决方案将是保存窗口状态的新基本形式。见下文。从FixedForm而不是Form:

派生您的表单
public partial class FixedForm : Form
{
    private FormWindowState lastWindowState;

    public FixedForm()
    {
        InitializeComponent();
    }

    protected override void OnVisibleChanged(EventArgs e)
    {
        base.OnVisibleChanged(e);

        if (Visible)
        {
            WindowState = lastWindowState;
        }
        else
        {
            lastWindowState = WindowState;
            WindowState = FormWindowState.Normal;
        }
    }
}

答案 3 :(得分:1)

找到了解决这些错误的方法。

首先,您需要为表单及其子项暂停绘制。我找到了一个非常有用的帖子here,它描述了如何做到这一点。

暂停绘制后,需要调用控件的UpdateBounds方法,并将ClientRectangle Width或Height增加1,然后将其减小回原来的值。这将调用布局功能,使所有内容都更新/重绘。最后一步是启用绘画。我想这不是一个很好的解决方案,但它确实有用。

StopDrawing();
UpdateBounds(Location.X, Location.Y, Width, Height, ClientRectangle.Width, ClientRectangle.Height + 1);
UpdateBounds(Location.X, Location.Y, Width, Height, ClientRectangle.Width, ClientRectangle.Height - 1);
StartDrawing();

我发现暂停绘画非常有用,不仅可以解决这两个错误,而且通常也可以使GUI工作更顺畅。我想这可以帮助消除任何类型的闪烁。但是,这个解决方案需要P / Invokes,一般应该避免使用。

答案 4 :(得分:0)

为什么不在创建窗口后手动重置menuStrip项目中的所需图标:

menuStripMain.Items[0].Image = null;