简体   繁体   English

FormClosing事件未调用MDI子表单

[英]FormClosing Event not called for MDI Child Form

I am trying to close a formular when opening a new one. 我打算在打开一个新的时候关闭一个公式。 When closing an formular, I want to process some special logic in the closing event. 关闭公式时,我想在结束事件中处理一些特殊逻辑。 But the closing event is never called, neither in the FormClosing nor in the Closing event, nor in the abstract base class nor in the given manual attached event form_FormClosing . 但是,在FormClosing和Closing事件中,也不在抽象基类中,也不在给定的手动附加事件form_FormClosing事件。

When I manual close the form by clicking the x all events are fired fine. 当我通过单击x手动关闭表单时,所有事件都被解雇了。 Invoking the Close() method fails. 调用Close()方法失败。

Do you have some recmmendations to fix my issue? 你有一些建议来解决我的问题吗?

MdiParent: 的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
}

Abstract generic mdi child form: 抽象通用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);
    }
 }

This misbehaves because the native Windows MDI implementation doesn't support hiding MDI child windows. 这是行为不端,因为本机Windows MDI实现不支持隐藏MDI子窗口。 Winforms uses a trick to still support Hide(), it actually destroys the native window and re-creates it when you call Show() again. Winforms使用技巧仍然支持Hide(),它实际上会破坏本机窗口并在再次调用Show()时重新创建它。 This has a side-effect however, the Close() call no longer raises the FormClosing/Closed events since the native window was already destroyed by the Hide() call. 这有副作用,但是Close()调用不再引发FormClosing / Closed事件,因为Native()调用已经破坏了本机窗口。 This is a bug, not uncommon in Winforms. 这是一个bug,在Winforms中并不罕见。

The workaround is simple, you don't need Hide() when you call Close(), just remove it. 解决方法很简单,当您调用Close()时不需要Hide(),只需将其删除即可。

Well I kept fighting and found the solution 好吧,我一直在战斗,找到了解决方案

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

This is Windows Forms ._. 这是Windows Forms ._。

This post has been useful to me also, although my case was slightly different. 这篇文章对我也很有用,虽然我的情况略有不同。

In this case avoiding _currentForm.Hide(); 在这种情况下避免_currentForm.Hide(); works fine because the code does a form-switch. 工作正常,因为代码执行表单切换。 I found that the problem also originates with a MDIChild that has been hidden by a different MDIChild that is on top. 我发现问题也源于一个MDIChild,它被一个位于顶部的不同MDIChild隐藏。

Here's a workaround that works also in that case based on the fact that Dispose is always called. 这是一种解决方法,在这种情况下也可以使用Dispose总是被调用的事实。

It can be done preparing something like this: 它可以做这样的准备:

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

Then in the code of MDIChildren just change the first row from 然后在MDIChildren的代码中只需更改第一行

public partial class AutoForm : Form {

to

public partial class AutoForm : FormExtenderClass {

Consider that is in any case a worarkound. 考虑到在任何情况下都是一个worarkound。 The main difference is that set e.Cancel=true will have no effect in the case that FormClosing is called from Disposed as backup. 主要区别在于,在从Disposed作为备份调用FormClosing的情况下,set e.Cancel=true将不起作用。

You can try this: 你可以试试这个:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM