WAIT-FOR { object-reference | type-name } : method-name ( [ parameters ] )
[ SET return-value ]
|
Provides the return value from the method, method-name( ), which is set when the WAIT-FOR statement completes execution. The
return-value can be a variable, property, or field that has the same data type as the
method-name( ) return value, typically
System.Windows.Forms.DialogResult.
To use this option, method-name( ) must be a non-VOID method. If you specify this option for a VOID method, such as
System.Windows.Forms.Application:Run( ), ABL raises a compile-time error.
The ABL-derived .NET class, r-WaitForms, inherits the
Progress.Windows.Form class to implement a non-modal .NET form. When you try to close the displayed form, a dialog box appears that prompts if you want the form to complete closing or not. If you choose to complete closing, the form closes. If you choose to cancel the closing, the form remains displayed, and you can try to close the form, again.
When you instantiate r-WaitForms, it initializes and subscribes a handler (the
Form_Closing( ) method) to the
FormClosing event of the form. You can then display the form by calling the
DoWait( ) method on the
r-WaitForms instance. This method executes the WAIT-FOR statement, which calls the .NET input-blocking method
System.Windows.Forms.Application:Run( ). (For more information on this method, see the notes.) When you try to close the displayed form, this causes the non-modal form to publish its
FormClosing event, which executes the
Form_Closing( ) method to handle the event.
USING System.Windows.Forms.* FROM ASSEMBLY.
USING Progress.Util.* FROM ASSEMBLY.
CLASS r-WaitForms INHERITS Progress.Windows.Form:
DEFINE VARIABLE rFormDescr AS CLASS Label NO-UNDO.
METHOD PUBLIC VOID DoWait( ).
/* Display and wait for the non-modal form to close */
WAIT-FOR Application:Run( INPUT THIS-OBJECT ).
END METHOD.
CONSTRUCTOR PUBLIC r-WaitForms( ):
/* Initialize and subscribe to events */
InitializeComponent( ).
THIS-OBJECT:FormClosing:Subscribe(Form_Closing).
END CONSTRUCTOR.
METHOD PRIVATE VOID InitializeComponent( ):
/* Initialize the non-modal form class and components */
rFormDescr = NEW Label( ).
/* Initialize the form description label */
rFormDescr:Text = "Click the Close (X) button of this form to pop-up
a dialog box ...".
rFormDescr:Size = NEW System.Drawing.Size( INPUT 330, INPUT 13 ).
rFormDescr:Location = NEW System.Drawing.Point( INPUT 4, INPUT 6 ).
/* Initialize the non-modal form */
THIS-OBJECT:FormBorderStyle = FormBorderStyle:FixedSingle.
THIS-OBJECT:Text = "This is my form.".
THIS-OBJECT:Controls:Add( INPUT rFormDescr ).
THIS-OBJECT:Size = NEW System.Drawing.Size( INPUT rFormDescr:Width, INPUT 60 ).
END METHOD.
|
METHOD PRIVATE VOID Form_Closing
( INPUT sender AS System.Object, INPUT e AS FormClosingEventArgs ):
DEFINE VARIABLE rDialog AS CLASS Progress.Windows.Form NO-UNDO.
DEFINE VARIABLE rDialogDescr AS CLASS Label NO-UNDO.
DEFINE VARIABLE rOKButton AS CLASS Button NO-UNDO.
DEFINE VARIABLE rCancelButton AS CLASS Button NO-UNDO.
DEFINE VARIABLE enDialogResult AS CLASS DialogResult NO-UNDO.
/* Create dialog box components */
ASSIGN
rDialog = NEW Progress.Windows.Form( )
rDialogDescr = NEW Label( )
rOKButton = NEW Button( )
rCancelButton = NEW Button( ).
/* Initialize the dialog description label */
rDialogDescr:Text = "Click OK to close form or click Cancel to leave form open.".
rDialogDescr:Size = NEW System.Drawing.Size( INPUT 306, INPUT 13).
rDialogDescr:Location = NEW System.Drawing.Point( INPUT 4, INPUT 6 ).
/* Initialize the buttons */
rOKButton:Text = "OK".
rOKButton:Size = NEW System.Drawing.Size( INPUT 60, INPUT 20).
rOKButton:Location = NEW System.Drawing.Point
( INPUT INTEGER( ( rDialogDescr:Width - 124 ) / 2 ),
INPUT rDialogDescr:Top + rDialogDescr:Height + 8 ).
rOKButton:DialogResult = DialogResult:OK.
rCancelButton:Text = "Cancel".
rCancelButton:Size = NEW System.Drawing.Size( INPUT 60, INPUT 20 ).
rCancelButton:Location = NEW System.Drawing.Point
( INPUT rOKButton:Left + rOKButton:Width + 4,
INPUT rDialogDescr:Top + rDialogDescr:Height + 8 ).
rCancelButton:DialogResult = DialogResult:Cancel.
/* Initialize the modal dialog box with label and buttons */
rDialog:FormBorderStyle = FormBorderStyle:FixedDialog.
rDialog:Controls:Add( INPUT rDialogDescr ).
rDialog:Controls:Add( INPUT rOKButton ).
rDialog:Controls:Add( INPUT rCancelButton ).
rDialog:Text = "My form is closing ...".
rDialog:Size = NEW System.Drawing.Size( INPUT 306, INPUT 106 ).
/* Display dialog box to handle FormClosing event and the results */
WAIT-FOR rDialog:ShowDialog( ) SET enDialogResult.
IF EnumHelper:AreEqual
( INPUT enDialogResult, INPUT DialogResult:Cancel ) THEN DO:
MessageBox:Show( INPUT "My form closing was canceled." ).
e:Cancel = TRUE. /* Cancel FormClosing; leave the main form open */
END.
ELSE DO:
MessageBox:Show( INPUT "My form is closing OK." ).
e:Cancel = FALSE. /* Continue FormClosing; close the main form */
END.
rDialog:Dispose( ). /* Dispose modal form object */
END METHOD. /* Form_Closing */
END CLASS.
|
The Form_Closing( ) method passes INPUT parameters from .NET for the
FormClosing event. One of these parameters (
e) is a
System.Windows.Forms.FormClosingEventArgs object, which contains a Cancel property whose setting allows the event handler to either complete the
FormClosing event or interrupt and cancel the
FormClosing event. To determine how to set this property, the event handler instantiates, initializes, and displays another
Progress.Windows.Form class (
rDialog) as a modal dialog box.
The dialog box contains two buttons, rOKButton and
rCancelButton, whose
DialogResult properties are set to the
System.Windows.Forms.DialogResult enumeration values OK and Cancel, respectively. The event handler displays
rDialog as a modal form by executing the WAIT-FOR statement, which calls the modal input-blocking method
System.Windows.Forms.Form:ShowDialog( ). (For more information on this method, see the notes.)
When you click one of the two dialog buttons, this causes the dialog box to close and the ShowDialog( ) method to return. This automatically sets the
DialogResult property on
rDialog to the value of the
DialogResult property on the button that you have clicked and also returns the same property value as the value of
ShowDialog( ), which the WAIT-FOR statement assigns to the variable,
enDialogResult. The event handler then uses the static
AreEqual( ) method on the
Progress.Util.EnumHelper class to test the value of
enDialogResult and set the
e:Cancel property to either complete the
FormClosing event or cancel the
FormClosing event and leave the non-modal form open for further input. The
Dispose( ) method call at the end of the event handler is required to allow the modal form object to be garbage collected (see the notes).
Note:
|
The calls to System.Windows.Forms.MessageBox:Show( ) display a message box similar to the ABL MESSAGE statement with the VIEW-AS ALERT-BOX option.
|
To instantiate r-WaitForms and display the non-modal form, you can thus run a procedure with code like this:
|
If you use any .NET forms in an ABL session, you can execute only one .NET WAIT-FOR statement that processes events for all .NET non-modal forms and their controls. This statement must be the first WAIT-FOR statement for processing non-modal events in your application. Following this statement, from event handlers and trigger blocks, you can execute multiple input-blocking statements to process any modal .NET form or ABL dialog box. ABL events for non-modal windows and their child widgets, or for non-GUI ABL features, such as asynchronous remote procedure calls and socket operations, all work in the context of this single non-modal .NET WAIT-FOR statement.
|
You can specify form-object-ref as an object reference to a single .NET non-modal form object, on which the WAIT-FOR statement blocks, displays, and waits to close. If you specify
form-object-ref, the statement also displays any additional non-modal forms that you have previously initialized by setting their Visible properties to TRUE or by invoking their
Show( ) methods. However, .NET automatically displays
form-object-ref, itself, without having to set its Visible property or run its
Show( ) method. You can also use triggers, event procedures, and .NET event handlers to create and display additional non-modal .NET forms (or ABL windows) after the WAIT-FOR statement blocks for events.
With form-object-ref, the WAIT-FOR statement unblocks and continues execution with the following statement if one of the following actions occurs:
|
The user clicks the form Close (X) button in the upper right corner of the form-object-ref form, and you do not cancel the action in a handler for the FormClosing event, as in the example. This action also automatically calls the form-object-ref:Close( ) method.
|
Caution:
|
If you are executing the READKEY statement within a trigger or event handler while blocking on a form-object-ref, and the user clicks the form Close ( X) button, the ABL application shuts down unconditionally. For example, the following READKEY loop can cause this shutdown to occur: DO WHILE LASTKEY != KEYCODE("F3"): READKEY. IF LASTKEY = KEYCODE("F3") THEN RETURN. END.
This shutdown occurs because .NET generates a WM_QUIT message in response to clicking the Close ( X) button that READKEY interprets (by design) as a message to shut down the application.
|
Caution:
|
You might have a problem displaying message boxes after invoking Application:Exit( ) or Application:ExitThread( ). One way this can happen: if you use any two of the techniques for unblocking the WAIT-FOR, such as by calling Close( ), then calling Application:Exit( ), any subsequent executions of the MESSAGE statement with the VIEW-AS ALERT-BOX option or any subsequent calls to System.Windows.Forms.MessageBox:Show( ) might not display the specified message box and the user will hear a beep sound instead.
|
If you do not specify form-object-ref, the statement displays and blocks for input on any non-modal forms that you have previously initialized by setting their
Visible properties to TRUE or by invoking their
Show( ) methods. Without
form-object-ref, you also do not need to have a .NET form instantiated before you execute the WAIT-FOR statement. Without any non-modal .NET form created, this statement processes ABL events until you create and initialize your first .NET non-modal form for display in an associated event handler or trigger, at which point the same WAIT-FOR statement processes both .NET and ABL events.
Also, if you do not specify form-object-ref, the WAIT-FOR statement unblocks and continues execution with the following statement only when you invoke the
System.Windows.Forms.Application:Exit( ) method at some point in the ABL session. This method closes all non-modal .NET forms that are currently open before unblocking the WAIT-FOR statement. Note that using this technique, you must be sure to create and initialize at least one .NET form or ABL window (non-modal or modal) so there are active components to work with during the input-blocking state. Otherwise, the blocking WAIT-FOR statement blocks indefinitely or until the user presses
CTRL+BREAK.
Note:
|
When working with any displayed non-modal form, except the form specified by form-object-ref, the user (using the Close ( X) button) or the application (using the Close( ) method) can close the form. However, this does not by itself unblock the blocking WAIT-FOR statement. If you want the WAIT-FOR to unblock other than by closing the form specified by form-object-ref, your application must call Application:Exit( ).
|
WAIT-FOR dialog-object-ref:ShowDialog ( [ parent-form ] )
|
This causes the WAIT-FOR statement to display the form specified by the dialog-object-ref object reference, and block for input on that form as a dialog box. You can also specify the object reference of a form (
parent-form) that becomes the parent of the dialog box referenced by
dialog-object-ref. (This allows the .NET dialog box to display centered over the parent form.)
Note:
|
The System.Windows.Forms.MessageBox class does not work this way. Instead, it is similar to the MESSAGE statement with the VIEW-AS ALERT-BOX option, which handles its own input without events. Similarly, you can only open a MessageBox by invoking its static Show( ) method outside of a WAIT-FOR statement.
|
With dialog-object-ref:
ShowDialog( ), the WAIT-FOR statement unblocks and continues execution with the following statement if one of the following actions occurs:
|
You set the dialog-object-ref:DialogResult property (if the form class supports it) to a valid System.Windows.Forms.DialogResult enumeration value.
|
|
You call the dialog-object-ref:Close( ) method. Note that calling this method also automatically calls the Dispose( ) method on the form, making the form object available for garbage collection.
|
For any of these actions, the FormClosing and
FormClosed events are also published on
dialog-object-ref, and you can handle the
FormClosing event in order to prevent the form from being closed by cancelling the action, as shown in the example.
Caution:
|
Unlike for non-modal forms, when the user clicks the Close (X) button on a dialog box, or when you set the value of the dialog-object-ref:DialogResult property, the .NET Framework does not automatically call the Close( ) method on dialog-object-ref and therefore does not also call the Dispose( ) method. Instead, .NET hides the form so it can be shown again without creating a new instance of the dialog box. Because of this behavior, when the form is no longer needed by your application, you must call the dialog-object-ref:Dispose( ) method to enable garbage collection for the form and all the .NET controls that it contains. If the form contains any ABL-derived controls (including any ABL-derived control containers, such as user controls), those controls will also not be garbage collected until you call Dispose( ), because the form itself is still holding a reference to them. Thus, calling Dispose( ) on the modal form also causes Dispose( ) to be called on these ABL-derived controls, which enables them for garbage collection, again, as long as there are no other references to them in the ABL session.
|
At this point, you can check the user response to the dialog box. Note that ShowDialog( ) returns a
DialogResult (enumeration) value with the result of the dialog box. You can access this value using the SET option (as shown in the
r-WaitForms.cls example) or by checking the
dialog-object-ref:DialogResult property (if the form object is still available and the class supports it).
Note:
|
Not all .NET form classes provide a public DialogResult property—for example, System.Windows.Forms.FileDialog. For a form that does not provide this property, you can handle dialog box results in the following ways: 1) by using the SET option to return the form’s ShowDialog( ) method value, 2) by using event handlers subscribed to the events that the form provides, for example, the FileOk or HelpRequest event, or 3) by testing the values of properties that might otherwise be set depending on input to the dialog box, such as the FileName property of the System.Windows.Forms.OpenFileDialog object.
|
|
The user clicks a button (or any control that implements the System.Windows.Forms.IButtonControl interface) contained by the dialog box whose DialogResult property you have set with a valid DialogResult enumeration value. In this case, .NET automatically sets the dialog-object-ref:DialogResult property to the value of the button property.
|
Otherwise, your application must set the value of dialog-object-ref:DialogResult directly, typically in an event handler. Note that if you want .NET to automatically set the
dialog-object-ref:DialogResult property from a button
DialogResult property, your application must initialize the
DialogResult value for the button property before the user clicks a given button.
|
You can detect that a specific form is closing by handling its FormClosing event; you can detect that a specific form has already closed by handling its FormClosed event. However, note that the Closed event does not fire for non-modal .NET forms that you close by calling Application:Exit( ) and that are not specified by the form-object-ref parameter passed to the Application:Run( ) method.
|
Caution:
|
Do not delete the ABL object reference to the object (sender) that publishes a FormClosing event from within its FormClosing event handler. This causes the FormClosing event to be published a second time. If you need to delete the sender for an event that is associated with closing a form before the AVM garbage collects it, execute the DELETE OBJECT statement for the sender within a handler for its FormClosed event.
|
Note:
|
.NET supports a Closing and Closed event on forms. However, use the FormClosing and FormClosed events, instead, because they work better.
|
|
The one WAIT-FOR statement that you execute for non-modal .NET forms after setting their Visible properties to TRUE or by invoking their Show( ) methods, must call the Application:Run( ) method to make the forms visible and usable. If you execute any other form of the WAIT-FOR statement after making non-modal .NET forms visible, such as one that blocks for an ABL event (even a developer event, such as U1 OF THIS-PROCEDURE), the ABL virtual machine (AVM) raises STOP on this WAIT-FOR statement.
|
|
You cannot set the Visible property or call the Show( ) method on a modal .NET form before executing a WAIT-FOR statement on the ShowDialog( ) method. If you execute a WAIT-FOR statement that calls the ShowDialog( ) method on a modal .NET form that you have previously made visible, .NET raises a run-time exception.
|
|
Once you execute a non-modal WAIT-FOR statement that calls the Application:Run( ) method, the statement goes into a wait state that allows any event handlers or triggers to run in response to all types of ABL-supported events, including .NET events, ABL UI events, and ABL non-UI events (such as socket events). In the associated event handlers or triggers, you can then create and display additional .NET non-modal forms (by setting their Visible properties or invoking their Show( ) methods) or ABL non-modal windows (for example, by setting their VISIBLE attributes to TRUE, executing DISPLAY statements, or executing a VIEW statement), and the existing WAIT-FOR statement processes events associated with these new non-modal .NET forms or ABL windows in addition to any other events it is already processing. To open modal dialog boxes (.NET or ABL) from an event handler or trigger, you must execute an additional WAIT-FOR statement for each dialog box that you open. Each such WAIT-FOR statement then blocks until its associated modal dialog box is closed, allowing the event handler or trigger that invoked the statement to resume execution.
|
Caution:
|
After you execute an additional WAIT-FOR statement that calls Application:Run( ), even if you trap the STOP condition with ON STOP, .NET does not allow another call to Applicaton:Run( ) in the same session. You must exit the ABL session and fix the application to avoid such simultaneous calls to Applicaton:Run( ).
|
|
You cannot invoke the non-modal .NET System.Windows.Forms.Application:Run( ) method or the .NET ShowDialog( ) method used to display a modal dialog box in any ABL context other than in a WAIT-FOR statement. Any attempt to do so raises a run-time error.
|