ABL.NET basic questions - Forum - OpenEdge Development - Progress Community
 Forum

ABL.NET basic questions

This question is answered

Hi,

I just started experimenting with ABL.NET GUI programming (and OOP as well), and now stumbling with few quite basic questions.

1. I have class constructor which draws my window. But before it does so, it should run some business controls to check if the window can be really started. If the result of such control is false, how can I prevent the window from starting ? I discovered that RETURN ERROR from constructor does the job, but is it the only and recommended option ?

2. How to simulate RETURN NO-APPLY in leave trigger of textbox to force user to enter correct value ?

3. How to implement business validation on pressing "Save" or "OK" button. Or specifically - how to stop window from write data if the result of validation is false ?

4. Is there something like {&SELF-NAME} which I can use inside the trigger ?

Any help would be appreciated :)

Piotr

Verified Answer
  • #2 - Mike Fechner answered this already:  Use the Validating event and set e:Cancel to TRUE (where e is the eventArgs parameter to the event handler).  I remember having the same Cancel button problem years ago when I first did GUI programming.  I can't remember what I did to handle that. I think there should be a property on the Cancel button.  For example, try setting the CausesValidation property to false.

    #3 - The window does not write data.  The window does nothing automatically.  If you just have a bunch of text boxes, for example, it is up to your code to do something with the values.  You could have an event handler for the OK button which will do whatever work you need to do.  Mike was talking about a Validate event, not a Validate method.  But I think just subscribing to the Click event of the OK button would work.

    If you are using data binding, that is a different story.  With data binding, updates that are made through a control will either be automatically propagated back to the data source (depending on the BindingSource settings), or it will use an event mechanism so that your code can make changes at the time of the user change.  If you don't know what I mean by data binding, then you don't need to worry about it right now!

    #4 - When an event handler runs, the first argument will always be the instance of the control that is sending the event.  You can always get its Type (obj:GetType()), and then access the Name (or FullName) property from that.

    #5 - Yup.  That is a .NET thing.  You cannot call Application:Run() a 2nd time after you have been kicked out of it.  Sorry.

  • I would forget about this Form:Validate() method.  I tired in in C# and I don't see that it is working either. I'm sure I'm doing something wrong.

    But you don't need it.  You need to subscribe to the Validating event on each control that you want to validate in this way.

    As I thought, the Validating event fires automatically when a control loses focus - so that you can validate and then set the Cancel property of the eventArgs if you want to prevent the user from leaving the control.  

    If you then want to do cross-field validation, you can just do it in the Click handler of the OK button.  You don't need to call Validate().  Just do the validation that you need to do right there by examining the values in whatever controls you need to look at.

All Replies
  • Thank you :)

    #2: Yes, setting CausesValidation to false did the trick

    #3: Yes, I am using databinding. I know I can call my validation logic from Click trigger on OK/Save button before I call Assign() on databinding source. This works. But I thought that this is what Validating (or Validated ?) methods on form level should do. The problem is, that calling THIS-OBJECT:VALIDATE() do not call these methods, even if subscription is done correctly (I assume it is, this was also generated by PDS).

    #4: OK. Sender:GetType() gives me the name of the class (in my case System.Windows.Forms.MaskedTextBox).

    CAST(sender,System.Windows.Forms.MaskedTextBox):NAME gives me what I need - the name of my widget. I did not find the way to get it without CASTing sender to specific type. But why CAST(sender,Sender:GetType()):NAME does not compile ?

    #5. OK, I will have to live with that it seems

  • On #4, you might also try:
     
    CAST (sender, System.Windows.Forms.Control):Name
     

    Architect of the SmartComponent Library and WinKit

    Consultingwerk Ltd.

  • #4: Yes, this works, thank you.

  • Re #3: How would the form's Validate method know what to call?  It is not omniscient! It is not the form's job to handle your data.  It is your job, as I said.  So it sounds like you've already got it under control.

    And I hadn't looked it up before but now have:  The Validate() method on the form simply causes the appropriate validate event to fire for the control that currently has focus:

    "Verifies the value of the control losing focus by causing the Validating and Validated events to occur, in that order."

    So that is another way to go - but you still have to subscribe to those events and do any necessary validation yourself.  I also think these events fire automatically when a control loses focus so that you can validate input as the user is entering data, and not wait until the end.  But sometimes there are cross-field dependencies and you do have to wait until OK is hit to validate these kinds of things.

    All this is pretty standard UI programming - the same as it is in the ABL.  There are just different properties/events in .NET.  There is no magic!

  • Yes, I know it's my job to handle and validate the the data :)

    What I didn't understand is, why validating method did not fire.

    Currently it looks like this:

    =============================================

    METHOD PRIVATE VOID tvdlg_Validating( INPUT sender AS System.Object, INPUT e AS System.ComponentModel.CancelEventArgs ):

     MESSAGE "Inside validating method" VIEW-AS ALERT-BOX.

    /* Validation logic goes here */

    RETURN.

    /*.......*/

    THIS-OBJECT:Validating:Subscribe(THIS-OBJECT:tvdlg_Validating).

    =============================================

    The code above was generated by PDS.

    And then in the click trigger of OK button I have:

    THIS-OBJECT:Validate().

    The above did not cause tvdlg_Validating to run.

    But I think I start to understand. "Verifies the value of the control losing focus"

    The form as such does not have the focus - only it's widgets have, so there is no meaning to have validating event on form level ? Was my mistake that in PDS I clicked on Validating event and created method for that ? Do I understand it correctly ?

  • I would forget about this Form:Validate() method.  I tired in in C# and I don't see that it is working either. I'm sure I'm doing something wrong.

    But you don't need it.  You need to subscribe to the Validating event on each control that you want to validate in this way.

    As I thought, the Validating event fires automatically when a control loses focus - so that you can validate and then set the Cancel property of the eventArgs if you want to prevent the user from leaving the control.  

    If you then want to do cross-field validation, you can just do it in the Click handler of the OK button.  You don't need to call Validate().  Just do the validation that you need to do right there by examining the values in whatever controls you need to look at.

  • OK. So my suspicion was right.

    Thank you all !

  • You could try the ValidateChildren() method on the form.
     
  • I'm refraining from responding more to this thread, but if you are curious when to use a self-terminating form that is also fully encapsulated functionally;  

    There is no control flow difference when the form terminates prematurely or continues on normally. This is normally a case when you have to display a form in the middle of a certain process where the form could be shown or not shown. Using the approach of handling the termination inside the Load event allows the caller code to be simplified to just NEW and SHOW (again, if there are no difference in control flow between normal and early termination). This way you don't have to special case the creation and showing of the form by checking additional condition.

    This should also handle SHOWDIALOG, if you assign the DialogResult property of the form to Cancel/No inside the Load event, it will have an effect of closing the dialog-box. This way your calling program will just need to do NEW, SHOWDIALOG, IF DialogResult = OK THEN for both normal and early termination.

    Note: I've used the first case. The ShowDialog, I have not.

  • The PDS ABL Dialog Box template includes the ShowModalDialog() method.

  • Got it re: ShowModalDialog.

    As to the rest, I would think the caller WANTS to know the difference between putting up a dialog that the user cancels out of vs, having a form that was never appropriate to show at all.  Writing code that obscures the fact that errors have happened doesn't seem good to me.  You did add the caveat " if there are no differences in control flow between normal and early termination".  But that would not seem like the normal case to me.

    But I will leave it at that.  It is of course up to Piotr to decide which way he wants to go.