Событие FormClosing не требуется для дочерней формы MDI - PullRequest
4 голосов
/ 09 января 2012

Я пытаюсь закрыть формуляр при открытии новой.При закрытии формул я хочу обработать некоторую специальную логику в событии закрытия.Но событие закрытия никогда не вызывается ни в FormClosing, ни в событии Closing, ни в абстрактном базовом классе, ни в данном событии, прикрепленном вручную form_FormClosing.

Когда я вручную закрываю форму, нажимаях все события сработали нормально.Вызвать метод Close() не удалось.

Есть ли у вас какие-либо рекомендации для решения моей проблемы?

MdiParent:

private Form _currentForm;
private void ShowForm<T>() where T : Form
{
    if (_currentForm != null && !_currentForm.IsDisposed)
    {
        _currentForm.Hide();
        _currentForm.Close();
    }

    var form = MdiChildren.FirstOrDefault(f => f.GetType() == typeof(T));
    if (form == null)
    {
        form = _formFactory.CreateForm<T>();
        form.MdiParent = this;
        form.WindowState = FormWindowState.Maximized;
        form.FormClosing += form_FormClosing;
        _currentForm = form;
        MdiBackground.Hide();
        form.Show();
    }
    else
    {
        ActivateMdiChild(form);
        form.Activate();
    }
}

void form_FormClosing(object sender, FormClosingEventArgs e)
{
    // will not be called
}

Абстрактная универсальная дочерняя форма mdi:

public abstract partial class BaseForm<TEntity> : Form where TEntity : class, IEntity
{
    protected override void OnClosing(CancelEventArgs e)
    {
        // wil not be called
        if (EditMode == EditModes.Editable)
        {
            MessageBox.Show(this, "Please commit or abort your changes");
            e.Cancel = true;
        }
        base.OnClosing(e);
    }
 }

Ответы [ 4 ]

6 голосов
/ 09 января 2012

Это ведет себя неправильно, потому что собственная реализация Windows MDI не поддерживает скрытие дочерних окон MDI.Winforms использует трюк для поддержки Hide (), он фактически разрушает собственное окно и создает его заново, когда вы снова вызываете Show ().Это имеет побочный эффект, однако вызов Close () больше не вызывает события FormClosing / Closed, поскольку собственное окно уже было уничтожено вызовом Hide ().Это ошибка, нередкая в Winforms.

Обходной путь прост, вам не нужно Hide (), когда вы вызываете Close (), просто удалите его.

1 голос
/ 09 января 2012

Ну, я продолжал бороться и нашел решение

if (_currentForm != null && !_currentForm.IsDisposed)
{
    // This call prevents calling the closing event -> _currentForm.Hide();
    _currentForm.Close();
}

Это Windows Forms ._.

0 голосов
/ 06 января 2013

Этот пост был мне полезен, хотя мой случай немного отличался.

В этом случае избегание _currentForm.Hide(); работает нормально, потому что код выполняет переключение форм. Я обнаружил, что проблема также связана с MDIChild, который был скрыт другим MDIChild, находящимся сверху.

Вот обходной путь, который также работает в этом случае, основываясь на том факте, что Dispose всегда вызывается.

Это можно сделать, подготовив что-то вроде этого:

public abstract class FormExtenderClass : Form{
    private bool formClosingFired = false;
    private bool formClosedFired = false;

    protected override void OnFormClosing(FormClosingEventArgs e) {
        base.OnFormClosing(e);
        formClosingFired = !e.Cancel;
    }

    protected override void OnFormClosed(FormClosedEventArgs e) {
        base.OnFormClosed(e);
        formClosingFired = true;
    }

    protected override void Dispose(bool disposing) {
        if (!formClosingFired) OnFormClosing(new FormClosingEventArgs(CloseReason.UserClosing, false));
        if (!formClosedFired) OnFormClosed(new FormClosedEventArgs(CloseReason.UserClosing));
        base.Dispose(disposing);
    }
}

Тогда в коде MDIChildren просто измените первую строку с

public partial class AutoForm : Form {

до

public partial class AutoForm : FormExtenderClass {

Считайте, что в любом случае это может быть недоразумением. Основное отличие состоит в том, что набор e.Cancel=true не будет действовать в случае, если FormClosing вызывается из Disposed в качестве резервной копии.

0 голосов
/ 09 января 2012

Вы можете попробовать это:

form1.Closing += delegate 
{
  // your logic
};
...