MDI子窗体关闭事件FormClosing未被调用

5
我正在尝试在打开新表单时关闭一个表单。 当关闭一个表单时,我希望在关闭事件中处理一些特殊的逻辑。 但是关闭事件从未被调用,在FormClosing和Closing事件中,也没有在抽象基类或给定的手动附加事件form_FormClosing中出现。
当我手动通过点击x关闭表单时,所有事件都会正常触发。但调用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个回答

7
这个问题的原因在于Windows本地MDI实现不支持隐藏MDI子窗口。Winforms使用一个小技巧来支持Hide(),它在你再次调用Show()时会摧毁本地窗口并重建它。然而,这也有一个副作用,由于本地窗口已经被Hide()调用摧毁了,Close()调用不再引发FormClosing/Closed事件。这是一个bug,在Winforms中很常见。 解决方法很简单,当你调用Close()时,无需使用Hide(),只需将其删除即可。

1

好的,我继续努力并找到了解决方案

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

这是 Windows Forms。


有人能告诉我它为什么会那样表现吗? - Rookian

0
你可以尝试这个:
form1.Closing += delegate 
{
  // your logic
};

0

这篇文章对我也很有用,尽管我的情况略有不同。

在这种情况下,避免使用_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 {

请注意这只是一种解决方法。主要区别在于,如果从备份的Disposed中调用FormClosing,则设置e.Cancel=true将不起作用。


这篇文章虽然发布已经有一段时间了,但它仍然救了我的命。谢谢! - user4676463

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接