Validating the Form
- Details
- Written by David Corrales
- Last Updated: 31 May 2023
- Created: 02 September 2011
- Hits: 32481
Documentation Update: The 'Cancel' property instructions in the 'Validating' event section was updated in May 2023.
A good user interface will validate user input to ensure it is in the correct format. This may come in the form of simply checking if there is an entry for a field, such as a name or a more complex task such as validating an email address. Thankfully WinForms has built in mechanisms to help facilitate data validation.
Each control has the following events and properties that are used to validate a form.
Validation Events:
Validating
This event occurs when the control is validating. Validation on a control is triggered when the control loses focus.
Use this event to provide custom validation for any input control, such as a TextBox. The Validating event passes a [System.ComponentModel.CancelEventArgs] object as a parameter to the event block, which you can access this by using the $_ variable.
$textbox1_Validating=[System.ComponentModel.CancelEventHandler]{ #Event Argument: $_ = [System.ComponentModel.CancelEventArgs] #If Validation fails tell the event to stop $_.Cancel = $true }
Set $_.Cancel to $true if you wish to cancel the action because of a validation failure. By doing so, this will retain focus on the control.
Set $_.Cancel to $false when the validation is successful and you wish to continue. All proceeding focus event(s) will follow.
If the Cancel property is set to True in the Validating event, all events that would usually occur after the Validating event are suppressed. In other words, the validating control will retain the focus until the user provides the correct format, even if the user clicks another control such as a button or textbox (i.e., the caret will remain in the textbox until the user enters the correct format).
Important: Never attempt to set the Focus of a control in this event because it can cause the script to hang.
Validated
This event occurs when the control is finished validating. Use this event to handle any needed upkeep after successfully validating the control.
Note: If the Validation was canceled in the Validating Event, then this event will not be called.
Validation Properties:
CausesValidation
This property indicates whether the control causes validation to be performed on any controls that require validation when it receives focus. A typical case where CausesValidation property is set to False is when there is a cancel button. There is no need to validate a control that loses focus when the user wishes to cancel out of the form; therefore, the button’s CausesValidation property can be set to false.
How do I validate a control?
As it turns out, validating controls depends on what type of control and the format of the data you wish to validate. Typically you will be validating text that is provided by a TextBox, but it could also come from a ComboBox where the user can type their selection. As for validating the text, it can range from simply ensuring there is value (i.e., not an empty string) or more complex task such as validating the format of an email address. The bad news is that you have to script your validation and it can change depending on the data type and format.
Tip: Use functions and code snippets. Never write the same validation function twice! Once you have written a validation function for a specific format, convert it into a snippet, so the next time you need to validate similar data, you will save time by simply inserting your snippet.
Validation Example 1: Checking if a TextBox Field is Empty
For the first example, we will create a simple function that will ensure the field is empty as well as making sure it doesn’t only contain blank spaces.
function Validate-IsEmptyTrim ([string] $field) { if($field -eq $null -or $field.Trim().Length -eq 0) { return $true } return $false }
Next add a Validating event to the TextBox:
$textboxName_Validating=[System.ComponentModel.CancelEventHandler]{ #Event Argument: $_ = [System.ComponentModel.CancelEventArgs] $_.Cancel = Validate-IsEmptyTrim $textboxName.Text }
In this example, we cancel the validation, when the field is empty or has only whitespaces. Since we are canceling, the focus will remain on the TextBox until the user enters the correct format.
How do I let the user know there is a validation failure?
You can use various techniques to notify a user. You can have a label to display the error message or change the foreground color of the TextBox or use a ToolTip control to display a popup message. A good solution is to use the ErrorProvider control. It displays an icon next to the control indicating an error as well as displaying an error message when the user hovers the mouse over the icon. For more details on the ErrorProvider control, refer to the Spotlight on the ErrorProvider article.
Let’s update Example 1 to display an Error Message using an ErrorProvider Control:
$textboxName_Validating=[System.ComponentModel.CancelEventHandler]{ #Check if the Name field is empty $_.Cancel = Validate-IsEmptyTrim $textboxName.Text if($_.Cancel) { #Display an error message $errorprovider1.SetError($textboxName, "Please enter your name."); } }
Next add a Validated event to clear in the ErrorProvider’s message. Since our event will only clear the error message, it can be used as a generic event shared by all validating controls. This is done by passing $this variable to the ErrorProvider’s SetError method. The $this variable represents the control that is calling the event.
$control_Validated={ #Pass the calling control and clear error message $errorprovider1.SetError($this, ""); }
Reminder: The Validated event will not be called if $_.Cancel was set to $True in the Validating event.
If you don’t want to use the $_.Cancel property in the Validating event (because users may not like it when they cannot select another field when the validation fails), then it is recommended to remove the Validated event and update the Validating event as follows:
$textboxName_Validating=[System.ComponentModel.CancelEventHandler]{ #Check if the Name field is empty $result = Validate-IsEmptyTrim $textboxName.Text if($result -eq $true) { #Display an error message $errorprovider1.SetError($textboxName, "Please enter your name."); } else { #Clear the error message $errorprovider1.SetError($textboxName, ""); } }
Validating Techniques:
Regular Expressions:
For more complex validation, such as validating an email address, you may need to rely on Regular Expressions. Regular expressions are useful because it allows you to match complex data by providing formatting information. In addition, PowerShell has built in support for regular expressions in the form of the –match operator.
Example use of a regular expression in PowerShell:
“PowerShell” -match “shell”
In this example we are matching any string that contains the word “shell”.
We will not go into details on how to use Regular Expressions, since it’s an extensive subject unto itself. We recommend referring to PowerShell’s about_Regular_Expressions help topic or type “PowerShell Regular Expressions” in a search engine for more information.
Leverage PowerShell’s Parameter Validation:
By using Parameter validation you can as validate TextBox values as well; although this isn’t necessary the best method. For more information on Parameter Validation refer to the about_functions_advanced_parameters help topic.
Validating Example 2: Using Parameter Validation
First, define a function that will use the function’s Parameter Validation attributes:
function ParameterValidate { Param( [Parameter(Mandatory=$true)] [ValidateNotNull()] [ValidateLength(1,10)] [String]$Text ) return $true }
Next modify the TextBox’s Validating event:
$textboxName_Validating=[System.ComponentModel.CancelEventHandler]{ #Init to False in case Validate Fails $_.Cancel = $true #Use Parameter Validation to Check TextBox value try{ $_.Cancel = -not(ParameterValidate $textboxName.Text) } catch #Catch any Parameter Errors { #$_ is now an Error in this scope $errorprovider1.SetError($textboxName, [string]$_.Exception.Message); } }
The resulting Error Message when the TextBox is empty:
Cannot validate argument on parameter ‘Text’. The number of characters (0) in the argument is too small. Specify an argument whose length is greater than or equal to “1″ and then try the command again.
As you can see this may not be the best error message to present to a user; therefore, you may have to customize your error messages.
Utilize the Appropriate Controls:
One can reduce the need to validate by using the appropriate controls for your data types:
DateTimePicker
Use this control when you need a date or time. This control will inherently validate the date field for you; therefore, you need not parse the date or use regular expressions,
MaskTextBox
Use this control when you need a phone number or other set format. The MaskTextBox insures the field is entered correctly by enforcing formatting. Depending on the format, you may still need custom validation for control or use the MaskTextBox’s built in validation for DateTime formats and number values. See Spotlight on the MaskedTextBox Control article for more details.
ComboBox
Use this control when you have a predetermined set of values that the user must select from.
CheckBox
Use this control when you have yes or no type question.
NumericUpDown
Use this control when you have integer values. This control allows you to specify a range of valid values.
TextBox
Use this control when you have text information such as a name. If there is a size constraint on the data, then use the TextBox’s the MaxLength property to limit the number of characters the user can enter. See Spotlight on the TextBox Control article for more details.
How to Trigger Validation when the Form is Closing:
If you have worked with validation in the past, you may have noticed that the unfocused controls do not trigger validation when the form closes. To get around the issue, you can explicitly tell the form to validate its child controls and react accordingly.
A good place to trigger the validation is in the form’s FormClosing event:
$form1_FormClosing=[System.Windows.Forms.FormClosingEventHandler]{ #Event Argument: $_ = [System.Windows.Forms.FormClosingEventArgs] #Validate only on OK Button if($form1.DialogResult -eq "OK") { #Validate the Child Control and Cancel if any fail $_.Cancel = -not $form1.ValidateChildren() } }
In the FormClosing event, we are checking if the user pressed the OK button, which has its DialogResult property set to “OK” (See Spotlight on the Button Control article for more details). By checking the DialogResult, we can bypass validation and allow the form to close when the user clicks on the cancel button or the X button in the upper right hand corner of the form’s window. Next we call the form’s ValidateChildren method which will trigger validation for all the controls contained in the form. The ValidateChildren method returns False if any of the controls fail validation. In the case where there is a validation failure, the $_.Cancel property is set to True and as a result prevents the form from closing.
Note: Preventing the form from closing is important when you are using multiple forms and are dependent on the returned data from the one form to be formatted correctly.
Handing Form Closing Validation without Canceling in the Validation event:
In the case where you are not setting the Validating $_.Cancel to True, which allows the control to lose focus, it is recommend to set a script scope variable that will flag when a control fails validation. The following is the modified Validation event for the control:
$textboxName_Validating=[System.ComponentModel.CancelEventHandler]{ #Check if the Name field is empty $result = Validate-IsEmptyTrim $textboxName.Text if($result -eq $true) { #Mark a failure only if the Validation failed $script:ValidationFailed = $true #Display an error message $errorprovider1.SetError($textboxName, "Please enter your name."); } else { #Clear the error message $errorprovider1.SetError($textboxName, ""); } }
The updated FormClosing event:
$form1_FormClosing=[System.Windows.Forms.FormClosingEventHandler]{ #Event Argument: $_ = [System.Windows.Forms.FormClosingEventArgs] #Validate only on OK Button if($form1.DialogResult -eq "OK") { #Init the Validation Failed Variable $script:ValidationFailed = $false #Validate the Child Control and Cancel if any fail $form1.ValidateChildren() #Cancel if Validation Failed $_.Cancel = $script:ValidationFailed } }
The updated FormClosing event initializes the $script:ValidationFailed variable to False. Any control that fails validation should set the variable to True, thus preventing the form from closing.
Helpful Validation Functions:
Finally, here are some common validation functions that you may find helpful:
function Validate-IsEmail ([string]$Email) { return $Email -match "^(?("")("".+?""@)|(([0-9a-zA-Z]((\.(?!\.))|"+` "[-!#\$%&'\*\+/=\?\^`\{\}\|~\w])*)(?<=[0-9a-zA-Z])@))"+` "(?(\[)(\[(\d{1,3}\.){3}\d{1,3}\])|(([0-9a-zA-Z][-\w]*"+` "[0-9a-zA-Z]\.)+[a-zA-Z]{2,6}))$" } function Validate-IsURL ([string]$Url) { if($Url -eq $null) { return $false } return $Url -match "^(ht|f)tp(s?)\:\/\/[0-9a-zA-Z]([-.\w]*[0-9a-zA-Z])*"+` "(:(0-9)*)*(\/?)([a-zA-Z0-9\-\.\?\,\'\/\\\+&%\$#_]*)?$" } function Validate-IsIP ([string] $IP) { return $IP -match "\b(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\."+` "(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\."+` "(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\."+` "(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b" } function Validate-IsEmptyTrim ([string]$Text) { if($text -eq $null -or $text.Trim().Length -eq 0) { return $true } return $false } function Validate-IsEmpty ([string]$Text) { return [string]::IsNullOrEmpty($Text) } function Validate-IsDate ([string]$Date) { return [DateTime]::TryParse($Date,[ref](New-Object System.DateTime)) }
[Note: These functions have been included as snippets in PowerShell Studio]
You can download the Validation Sample Forms.
For licensed customers, use the forum associated with your product in our Product Support Forums for Registered Customers.
For users of trial versions, please post in our Former and Future Customers - Questions forum.