C#.NET ошибки MDI при программном скрытии и повторном отображении развернутой дочерней формы, а также при развернутом значке дочерней формы невозможно изменить

В основном у меня две проблемы с C#.NET МДИ. Вы можете скачать решение 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;
}

когда дочерняя форма максимизирована, затем программно скрыта и показана снова, она становится чем-то вроде этого (обратите внимание на панель меню-управление дочерней формой появится окно, но дочерняя форма не развернута):

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 пиксель, дочерняя форма становится развернутой, как и должна быть, и значок дочерней формы в строке меню обновляется должным образом, и вам не нужен другой обходной путь, описанный выше. Если я изменяю размер формы programicaly, форма мерцает на 1 пиксель, и я не могу этого сделать, когда родительская форма развернута. Есть ли способ, как я могу вызвать функцию перерисовки / обновления, которая вызывается при изменении размера формы и которая делает дочернюю форму развернутой правильно, а значок в строке меню обновлен?

5 ответов


существует ошибка в реализации внутреннего класса MdiControlStrip, элемента управления, который отображает значок и символы min/max / restore в Родительском окне. Я еще не охарактеризовал его, код не так прост. Классический побочный эффект ошибки заключается в том, что глифы удваиваются, вы нашли некоторые другие побочные эффекты. Исправление просто, хотя, задержите создание дочерних окон до тех пор, пока конструктор не будет завершен. Вот так:

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

вы устали использовать Hide / Show вместо настройки visible на true / false?

попробуй:

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

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

Как насчет этого метода?

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 вместо 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;
        }
    }
}

нашли способ, как обойти эти ошибки.

прежде всего вам нужно приостановить рисование для формы и ее детей. Я нашел очень полезную тему здесь, который описывает, как это сделать.

после приостановки рисования вам нужно вызвать метод UpdateBounds элемента управления и увеличить ширину или высоту ClientRectangle на единицу, а затем уменьшить его до того же значения, что и раньше. Это вызывает функциональность макета, которая делает все, чтобы обновление / перекраска. Последний шаг-включить рисование. Не очень хорошее решение, я думаю, но оно работает.

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, чего следует избегать в целом.


почему бы просто вручную не сбросить необходимый значок в элементах menuStrip, после создания окна:

menuStripMain.Items[0].Image = null;