S
Stephan Zaubzer
Hi
While developing a Windows forms application I encountered what I
consider to be a bug or a design flaw:
Consider to have 3 Forms namely A B and C. B is owned by A and C is
owned by B. If we close A, all three forms should close which is exactly
the design described in the class library reference on msdn.
However, if the windows run in NON modal mode (i.e. not showed using
ShowDialog(IWin32Window), closing A does call the OnFormClosing on A and
on B but NOT on C. C gets closed without a way to check for unsaved
data, because the FormClosing event doesn't get raised.
If window B and C run in Modal mode (ShowDialog(IWin32Window)), C raises
the FormClosingEvent (from within the OnFormClosing Method), but setting
e.cancle = false will NOT prevent the window from closing, and even
worse, the OnFormClosing method will run AFTER the window has already
been disposed.
Possible Reason:
The invaluable resource .NET Reflector gave me some insight to the
Implementation of the System.Windows.Forms.Form class. When a window
closes, it calls OnFormClosing on all of its MdiChildren and Owned
Windows. If e.cancle does not evaluate to false after these calls, the
form gets Disposed. Dispose(bool disposing) calls Dispose on all owned
forms, and thus it works recursively. But OnFormClosing does NOT. So
when I call A.Close() it "asks" B to close, and if B does not set
e.cancle, A disposes itself which in turn disposes B and C. So C gets
Disposed without a prior call to OnFormClosing and no event rising.
Shouldn't the (private) WMClose method in System.Windows.Forms.Form call
some RECURSIVE method to check recursively for all owner relationships
if the owned forms (in all levels of the owner relationship) can close?
Possible workaround: (NOT tested yet)
override the OnFormClosing method that it calls OnFormClosing for all
owned forms recursively. This however will cause the OnFormClosing
method to be called twice for all owned forms that are directly owned by
the "root" form, because WMClose calls OnFormClosing on all its directly
owned forms, and later calls this.OnFormClosing.
The loop which calls OnFormClosing for all owned forms shouldn't be in
WMClose but rather in OnFormClosing itself, thus be recursive.
For MdiWindows this problem does not exist, because MdiCild Relations
can only exist in one level, so for MdiChildren this problem does not
exist. But when one closes the MdiParent of an MdiChild which owns some
window X, OnFormClosing and the FormClosing Event will NOT be called for X.
Has anyone ever encountered problems with this behavior as I did? And
how did you solve the problem?
I would consider this behavior either a bug or a design flaw!
Regards
Stephan
While developing a Windows forms application I encountered what I
consider to be a bug or a design flaw:
Consider to have 3 Forms namely A B and C. B is owned by A and C is
owned by B. If we close A, all three forms should close which is exactly
the design described in the class library reference on msdn.
However, if the windows run in NON modal mode (i.e. not showed using
ShowDialog(IWin32Window), closing A does call the OnFormClosing on A and
on B but NOT on C. C gets closed without a way to check for unsaved
data, because the FormClosing event doesn't get raised.
If window B and C run in Modal mode (ShowDialog(IWin32Window)), C raises
the FormClosingEvent (from within the OnFormClosing Method), but setting
e.cancle = false will NOT prevent the window from closing, and even
worse, the OnFormClosing method will run AFTER the window has already
been disposed.
Possible Reason:
The invaluable resource .NET Reflector gave me some insight to the
Implementation of the System.Windows.Forms.Form class. When a window
closes, it calls OnFormClosing on all of its MdiChildren and Owned
Windows. If e.cancle does not evaluate to false after these calls, the
form gets Disposed. Dispose(bool disposing) calls Dispose on all owned
forms, and thus it works recursively. But OnFormClosing does NOT. So
when I call A.Close() it "asks" B to close, and if B does not set
e.cancle, A disposes itself which in turn disposes B and C. So C gets
Disposed without a prior call to OnFormClosing and no event rising.
Shouldn't the (private) WMClose method in System.Windows.Forms.Form call
some RECURSIVE method to check recursively for all owner relationships
if the owned forms (in all levels of the owner relationship) can close?
Possible workaround: (NOT tested yet)
override the OnFormClosing method that it calls OnFormClosing for all
owned forms recursively. This however will cause the OnFormClosing
method to be called twice for all owned forms that are directly owned by
the "root" form, because WMClose calls OnFormClosing on all its directly
owned forms, and later calls this.OnFormClosing.
The loop which calls OnFormClosing for all owned forms shouldn't be in
WMClose but rather in OnFormClosing itself, thus be recursive.
For MdiWindows this problem does not exist, because MdiCild Relations
can only exist in one level, so for MdiChildren this problem does not
exist. But when one closes the MdiParent of an MdiChild which owns some
window X, OnFormClosing and the FormClosing Event will NOT be called for X.
Has anyone ever encountered problems with this behavior as I did? And
how did you solve the problem?
I would consider this behavior either a bug or a design flaw!
Regards
Stephan