DisposeDialogOnClose bug

Posted by Lieven De Foor on 09-Jan-2018 04:57

According to the OpenEdge documentation (documentation.progress.com/.../index.html and StackOverflow/Microsoft (stackoverflow.com/.../3097383a Form that is not shown modally, gets disposed on Close(). When the Form is shown modally (i.e. ShowDialog()), the Dispose does not happen automatically and you need to call Dispose() yourself.

Progress thought it would be helpful to provide a way to by default have the Form dispose when it's closed as Dialog as well.

While this seems reasonable, there is a bug in the implementation:

In the Microsoft implementation, when closing a non-modal Form, the Dispose happens AFTER the form has closed (i.e. after OnFormClosed())

In the OpenEdge implementation of DisposeDialogOnClose, when closing a modal Form, the Dispose happens INSIDE the OnFormClosed() method of Progress.Windows.Form.

This can be seen by looking at the stack trace when overridding OnFormClosed and subscibing the Disposed event of a Form and closing the screen.

This causes code that uses the FormClosed event of the Form to no longer be able to access properties of the Form when started as dialog, while still being available when started non-modally!

In my particular case I'm saving some screen settings in FormClosed, and this fails when the same Form is shown as dialog, since the form is already disposed...

I'm trying a workaround now by setting DisposeDialogOnClose to false, and calling the Dispose() method myself at the very end of OnFormClosed(), but that will still cause problems for classes inheriting from my base form class...

All Replies

Posted by Matt Gilarde on 09-Jan-2018 06:36

You may be able to work around this by subscribing to the FormClosing event and saving the screen settings in that handler. FormClosing should be generated before FormClosed disposes the form.

Posted by Lieven De Foor on 09-Jan-2018 09:12

Hi Matt,

Yes, FormClosing is an option, but that can be cancelled, and I don't want to save anything when that happens.

Saving preferences was just an example though, a subscriber to the FormClosed event should not need to worry that the sender is already disposed/disposing when started as Dialog...

I have currently worked around the problem like this:

METHOD OVERRIDE PROTECTED VOID OnFormClosed(e AS System.Windows.Forms.FormClosedEventArgs):

        DEFINE VARIABLE disposeOnClose AS LOGICAL NO-UNDO.

        IF Modal AND DisposeDialogOnClose
        THEN ASSIGN
                disposeOnClose = TRUE
                DisposeDialogOnClose = FALSE.

        /* snip... */

        SUPER:OnFormClosed(e).

        /* snip... */

        IF disposeOnClose
        THEN Dispose().

    END METHOD.

but that doesn't prevent inherited classes to create a problematic scenario...

I could make the OnFormClosed FINAL and have a BeforeFormClosed and AfterFormClosed method that are overridable:

METHOD OVERRIDE PROTECTED FINAL VOID OnFormClosed(e AS System.Windows.Forms.FormClosedEventArgs):

        DEFINE VARIABLE disposeOnClose AS LOGICAL NO-UNDO.

        IF Modal AND DisposeDialogOnClose
        THEN ASSIGN
                disposeOnClose = TRUE
                DisposeDialogOnClose = FALSE.

        BeforeFormClosed(e).

        SUPER:OnFormClosed(e).

        AfterFormClosed(e).

        IF disposeOnClose
        THEN Dispose().

    END METHOD.

but that's not making things less complicated...

Posted by Laura Stern on 09-Jan-2018 09:32

Regarding the statement that "FormClosing is an option, but that can be cancelled" - yes, but it would be cancelled by the application itself.  .NET is not going to cancel it.  So they have total control over whether the form gets closed or not.  I agree with Matt that they should have their code in the FormClosing event.  

Posted by Mike Fechner on 09-Jan-2018 12:23

Why don't you perform your activities before the SUPER:OnFormClosed in the OnFormClosed override? That would be called before OpenEdge executes the Dispose() methods.

"but that will still cause problems for classes inheriting from my base form class..."

I see that point. But sometimes it just requires coding conventions.

Posted by Lieven De Foor on 10-Jan-2018 02:00

[quote user="Mike Fechner"]

Why don't you perform your activities before the SUPER:OnFormClosed in the OnFormClosed override? That would be called before OpenEdge executes the Dispose() methods.

[/quote]

I have a UserControl subscribing to the FormClosed of its ParentForm, so there is no such fine granularity there (in the FormClosed event handler the ParentForm is already disposed).

While there are a number of more or less usable workarounds, I still think this is a bug that should at least get documented since this is unexpected behaviour...

Posted by Mike Fechner on 10-Jan-2018 02:08

That's a matter of interpretation :-)

But when Progress is tied to the limits allowed by the .NET WinForms framework, Progress might just not be able to fix what you call a bug.

Posted by Lieven De Foor on 10-Jan-2018 02:12

Sure Mike, I also think Progress can't fix this (might have to take a look at the .NET framework reference source to be sure: referencesource.microsoft.com/)

Still, at least this forum thread can help people bumping into this...

Posted by Mike Fechner on 10-Jan-2018 02:18

Awareness is always great!

This thread is closed