C#.NET MDI在以编程方式隐藏并再次显示最大化的子窗体以及最大化时的子窗体';s图标无法更改

C#.NET MDI在以编程方式隐藏并再次显示最大化的子窗体以及最大化时的子窗体';s图标无法更改,c#,.net,mdi,C#,.net,Mdi,基本上,我在使用C#.NET MDI时遇到了两个问题。您可以下载复制bug的VS2010解决方案 1) 当以编程方式隐藏并再次显示最大化的子窗体时,它不会再次正确地最大化,并且既不会最大化,也不会处于正常状态 childForm = new Form(); childForm.Text = "Child Form"; childForm.MdiParent = this; ... private void showButton_Click(object sender, EventArgs e

基本上,我在使用C#.NET MDI时遇到了两个问题。您可以下载复制bug的VS2010解决方案

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;
}
当子窗体被最大化,然后以编程方式隐藏并再次显示时,它会变成这样(请注意菜单栏-子窗体的控制框出现,但子窗体未被最大化):

在此阶段,子窗体不能四处移动。但是,我找到了一个解决方法,只需显示和隐藏一个虚拟子窗体,这将强制实际的子窗体正确地最大化。但这会使MDI区域闪烁。尝试了无效、刷新和更新方法,但没有帮助。也许还有其他的解决办法来克服这个错误,而不是让MDI区域在虚拟子窗体中闪烁

private void workaround1Button_Click(object sender, EventArgs e)
{
    dummyForm.Visible = true;
    dummyForm.Visible = false;
}
2) 当子窗体最大化时,子窗体的图标将显示在菜单栏上。但是,如果必须在子窗体最大化时更改图标,则不会刷新菜单栏上的图标(请参见上图)。我也找到了一个解决方法,它基本上隐藏和显示菜单栏。图标会刷新,但它会使菜单栏下的所有内容闪烁。尝试了无效、刷新和更新方法,但没有帮助。是否有其他方法使菜单栏刷新子窗体的图标

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


我还注意到,当父窗体处于正常窗口状态模式(未最大化)时,您将窗体的宽度或高度更改1个像素,子窗体将按原样最大化,菜单栏上的子窗体图标将正确刷新,您不需要上述其他解决方法。如果我通过编程更改窗体的大小,窗体将闪烁1个像素,当父窗体最大化时,我无法这样做。有什么方法可以调用重绘/刷新功能吗?重绘/刷新功能是在调整窗体大小时调用的,它可以使子窗体正确地最大化,并刷新菜单栏上的图标

您是否厌倦了使用Hide/Show而不是将visible设置为true/false

尝试:


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

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

这个变通方法怎么样

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;
}
更新

我只是告诉你怎么做。使用与上面相同的思想的更好的解决方案是一个新的基本表单,它可以保存windows状态。见下文。从FixedForm而不是表单派生表单:

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

找到了一种绕过这些虫子的方法

首先,您需要暂停一个窗体及其子窗体的绘画。我发现了一个非常有用的线程,它描述了如何做

挂起绘制后,需要调用控件的UpdateBounds方法,将ClientRectangle的宽度或高度增加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();


我发现暂停绘制不仅对解决这两个bug非常有帮助,而且总体上对使GUI工作更加顺利也非常有帮助。我想这有助于消除任何闪烁。但是,此解决方案需要P/Invokes,这通常应该避免。

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

menuStripMain.Items[0].Image = null;

是的,我试过了,但没什么变化。我认为childForm.Visible=true/false调用这些方法。实际上应该是相反的。Hide/Show然后应将visible设置为false/true。啊,是的,您使用了Load事件。将base.OnLoad()移到底部。在我的机器上工作™.通过重写OnLoad方法尝试了修复,但仍然存在相同的错误行为。没有什么变化。而且子窗体需要动态创建,所以这对我来说不是一个真正的解决方案。当然,这是克服错误的可能性之一,但它会使子窗体的动画一次又一次地出现,这有点烦人。我的解决方法更快。如果解决了问题,您可以向父窗口句柄发送
WM\u SIZE
消息。
menuStripMain.Items[0].Image = null;