Created On:  11 December 2012

Problem:

Customer has a .NET Windows Form application written in Visual COBOL.  The form has several textbox controls on it and it uses auto validation by setting their CausesValidation property to true.

This works fine when a user leaves the field except when they click on a button that causes a FormClose event to fire, such as invoke self::Close or clicking on the Windows Close "X" box.

The problem is that the Validating event occurs before the FormClosing event so the validation code will be executed when it really should be bypassed so that error messages are not displayed etc.

How can this be programmed so that the validation code is bypassed if the form is closed?

Resolution:

There is a sample program attached that demonstrates how this can be done by checking the current stack for the form to see if the WmClose message is present before executing the validation logic.

If WmClose is found then the logic will be bypassed and the validation will suceed so that the form will close.

Here is the sample code:

*----------------------------------------------------------------------------
*                              Test Validate
*
* This example program demonstrates how to circumvent the problem that occurs
* when a Windows Form is closed and implicit validation of controls is being
* used on the Form. The problem is that the Validating event for the controls
* actually occurs before the FormClosed event so the Validating logic is in
* effect even when the Form is closed.
*
* This example shows you how this can be bypassed by adding a method call in
* the Validating event handler which will check the stack for the WmClose
* method and if it exists the validation code will be bypassed and the form
* will be closed without displaying error message box.
*
* Run this application and type an invalid entry into the textbox (not Yes or
* No) and then click the Close button or the Close "X" on the window.
* The Validation logic will be bypassed and the form will close.
*----------------------------------------------------------------------------

class-id testvalidate.Form1 is partial
   inherits type System.Windows.Forms.Form.
working-storage section.
method-id NEW.
procedure division.
   invoke self::InitializeComponent
   invoke textBox1::Focus
   goback.
end method.
method-id IsFormClosing public.
local-storage section.
78 WMCLOSE value "WmClose".
01 stackTrace type System.Diagnostics.StackTrace.
01 stframes type System.Diagnostics.StackFrame occurs any.
01 MethodName type System.Reflection.MethodBase.
procedure division returning FormIsClosing as condition-value.
  
   set
FormIsClosing to false
   set stackTrace to new System.Diagnostics.StackTrace
   set stframes to stackTrace::GetFrames
   perform varying sf as type System.Diagnostics.StackFrame thru stframes
      set MethodName to sf::GetMethod
      if MethodName::Name = WMCLOSE
         set FormIsClosing to true
         exit perform
      end-if
   end-perform
   goback.
end method.
method-id textBox1_Validating final private.
procedure division using by value sender as object e as type System.ComponentModel.CancelEventArgs.
   if self::IsFormClosing = false
      if textBox1::Text = "Yes" or "No"
         continue
      else
         invoke type MessageBox::Show("Must be Yes or No")
         set e::Cancel to true
      end-if
   end-if.
end method.
method-id buttonCancel_Click final private.
procedure division using by value sender as object e as type System.EventArgs.
   invoke self::Close
end method.
end class.

Incident #2604488