FormClosing event not triggered by MDI child form

I try to close the form when opening a new one. When closing the form, I want to process some special logic in closing. But the closing event is never called either in the FormClosing event, or in the closure, or in the abstract base class, or in this manually attached form_FormClosing event.

When I manually close the form by clicking x, all events will be deleted in order. A call to the Close() method fails.

Do you have any recommendations for fixing my problem?

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 common child form of 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
source share
4 answers

This is not true because the native Windows MDI implementation does not support hiding MDI child windows. Winforms uses the trick to support Hide (), it actually destroys its own window and recreates it when you call Show () again. This has a side effect, however, calling Close () no longer triggers the FormClosing / Closed event, since the native window has already been destroyed by the Hide () call. This is a mistake, not uncommon in Winforms.

The workaround is simple, you do not need Hide () when you call Close (), just delete it.

+6
source

Well, I continued to fight and found a solution

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

This is Windows Forms._.

+1
source

You can try the following:

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

This post was useful to me, although my case was a little different.

In this case, avoidance _currentForm.Hide(); works fine because the code does the form switcher. I found that the problem is also related to MDIChild, which was hidden by another MDIChild, which is on top.

Here's a workaround that works in this case too, based on the fact that Dispose always called.

You can do 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 MDIChildren code just change the first line from

 public partial class AutoForm : Form { 

to

 public partial class AutoForm : FormExtenderClass { 

Consider this a concern anyway. The main difference is that set e.Cancel=true will have no effect when FormClosing is called from Disposed as backup.

0
source

Source: https://habr.com/ru/post/1390082/


All Articles