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

发布于 2024-10-07 01:23:30 字数 1459 浏览 0 评论 0原文

基本上我在使用 C#.NET MDI 时遇到两个问题。您可以在此处下载重现错误的 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;
}

变成这样(请注意菜单栏 - 子窗体的控制框出现,但子窗体未最大化):

当子窗体最大化,然后以编程方式隐藏并再次显示时,它会 sstatic.net/HIoaY.png" alt="alt text">

在此阶段,子表单无法移动。然而,我找到了一个解决方法,只需显示和隐藏一个虚拟子窗体,这会强制实际子窗体正确最大化。但这使得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 个像素,并且当父表单最大化时我无法执行此操作。有什么方法可以调用重绘/刷新功能,该功能在调整表单大小时调用,并使子表单正确最大化并刷新菜单栏上的图标?

Basically I am having two problems with C#.NET MDI. You can download VS2010 solution which reproduces bugs here.

1) When programmatically hiding and showing again a maximized child form, it is not maximized properly again and becomes neither maximized or in normal state.

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

When child form is maximized, then programicaly hidden and shown again, it becomes something like this (please notice the menu bar - child form's control box appears, but child form is not maximized):

alt text

At this stage, child form cannot be moved around. However, I found a workaround for that, simply by showing and hiding a dummy child form, which forces the actual child form to become properly maximized. But this makes MDI area to flicker. Tried Invalidate, Refresh, Update methods, but they don't help. Maybe there are other workarounds to overcome this bug and not to make MDI area flicker with dummy child form?

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

2) When child form is maximized, the icon of the child form is displayed on menu bar. However, if you have to change the icon while the child form is maximized, the icon on the menu bar is not being refreshed (see the image above). I found a workaround for that too, which basically hides and shows menu bar. Icon gets refreshed, but it makes everything below menu bar to flicker. Tried Invalidate, Refresh, Update methods, but they don't help. Is there any other way to make menu bar to refresh the child form's icon?

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

Also I noticed that when parent form is in normal window state mode (not maximized) and you change the width or height of the form by 1 pixel, child form becomes maximized as it should be and child form's icon on menu bar gets refreshed properly and you don't need other workaround I described above. If I change the size of the form programicaly, form flickers by 1 pixel and I cannot do that, when parent form is maximized. Is there any way how I could invoke the repaint/refresh functionality which is called when you resize a form and which makes child form become maximized properly and the icon on the menu bar refreshed?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

半枫 2024-10-14 01:23:30

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

There's a bug in the implementation of the internal MdiControlStrip class, the control that displays the icon and the min/max/restore glyphs in the parent window. I haven't characterized it as yet, the code isn't that easy. A classic side effect of the bug is that the glyphs get doubled up, you found some other side-effects. The fix is simple though, delay creating the child windows until after the constructor is completed. Like this:

    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);
    }
月下凄凉 2024-10-14 01:23:30

您是否厌倦了使用隐藏/显示而不是设置可见为真/假?

尝试:

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

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

Have you tired using Hide/Show instead of setting visible to true/false?

Try:

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

private void hideButton_Click(object sender, EventArgs e)
{
    childForm.Hide();
}
暮光沉寂 2024-10-14 01:23:30

这个解决方法怎么样?

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 状态的新基本表单。见下文。从 FixForm 而不是 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;
        }
    }
}

How about this workaround?

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

UPDATE

I just gave you the idea how you could do. A better solution using the same idea as above would be a new base form which saves the windows state. See below. Derive your forms from FixedForm instead of 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;
        }
    }
}
划一舟意中人 2024-10-14 01:23:30

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

首先,您需要暂停窗体及其子窗体的绘制。我在这里找到了一个非常有用的线程,其中描述了如何操作。

暂停绘制后,您需要调用控件的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();

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

Found a way how to come around those bugs.

First of all you need to suspend painting for a form and its children. I found a very helpful thread here, which describes how to do it.

After suspending painting, you need call UpdateBounds method of the control and increase ClientRectangle Width or Height by one and then decrease it back to the same value it was before. This invokes layout functionality which makes everything to update/repaint. Last step is to enable painting. Not very nice solution I guess, but it works.

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

I find suspending painting very helpful not only for working around those two bugs, but also in general to make GUI work more smoothly. I guess this can help to remove any kind of flickering. However, this solution requires P/Invokes, which should be avoided in general.

最终幸福 2024-10-14 01:23:30

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

menuStripMain.Items[0].Image = null;

Why not just manually reset required icon in menuStrip items, after the creation of the window:

menuStripMain.Items[0].Image = null;
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文