One of the most critical foundations of an app's data integrity and consistency is covered in this post: Data input validation.
As you've seen on my previous post on how to build MD forms, when there are no validations, a user can enter (or not) whatever she wants and not necessarily what's good for the app and not what you planned she would.
It's critical for an app, to have 100 percent control over what a user can or cannot enter during his session. Less than that and you are in trouble.
In order to achieve full control we must treat every input object as a potential risk to our app. We always have to think of the only valid entry a user can input and then we validate it accordingly. On this post I will continue working with the car registration form (example9). This time we will work with example9b so make sure you've downloaded my latest files from my GitHub repo.
Dot Net framework has a very good implementation of error validation and MDIX has done a wonderful job on styling error items. I have ported the essential part of it to PS, so it can be also implemented natively in PowerShell. There is no C# code injected in my PowerShell script. Many PS programmers fall into this trap of copying and pasting C# code found all over the internet. I call it C# in disguise... IMHO I think It breaks the PowerShell flow and makes things unclear as of what they do and why. We are proud PowerShell developers and we should keep our code PowerShellish :-)
I called this function 'Set-ValidationError' (stored in the CommonFunctions file) It accepts a UI control as an input. There are four validation actions we can use for this UI control:
mark it as an element with a validation error (mark it as invalid)
set the error message that will be displayed near the control
clear the element's error state (mark it as valid)
return the state of an element. $true if it's in invalid state and $false if valid Yeah, its confusing cause $true makes more sense to be valid, but that's how Microsoft implemented it and I wanted to be consistent.
The other function (or series of functions) deals with the condition logic, for example checks if the element's text property is null or not. We can implement as many functions as we want, depending on the app's logic. For example, we can also check for a numeric values range, dates range etc.
Those functions are named Confirm-xxxxxField. For example, the 'Confirm-TextPatternField' function will check if the input matches a regular expression pattern, like a license plate that has to be in a format of 999-99-999 (3 digits, dash, 2 digits, dash, 3 digits). If not matching, it will mark the element as invalid. An invalid element will get a red border with a red error message near it (default is beneath the element). In the figure below you see three elements that are invalid:
This is one area where you control the conditions of an input. You decide, based on your app's needs, what are the conditions that will make an element invalid. By clicking apply on our example, the app will scan all of the must-be-validated elements, and will show their errors, if any.
Another area of control is the character input masking. For example, You can decide how many characters can a user type on a specific element. That's a simple MaxLength Xaml attribute. You can also control what characters are approved or blocked as an input. This is done by a function I wrote, called Confirm-TextInput that you attach to a 'add_TextChanged ' event. This function checks the characters entered by the user and blocks them, if needed, by matching them to a regular expression. It has at least one down side that I've found - when a user selects part of the text and hits a blocked key, the selected part will be deleted. Although it looks a bit wrong, think about the selection action. When we select something and type, it usually means we want to replace the selected part with some new text. So I feel comfortable with that... In our example, the Owner field is limited to letters and spaces, Plate is limited to digits and dashes and the Note field blocks most of the special characters.
You should always try to limit the characters a user can insert, because you can never know if an attacker could take advantage of an unknown PS vulnerability. A classic example would be SQL injection, where an attacker enters code into an innocent textbox, causing the app's code to break and execute his code, allowing him to hack into the system. Another reason is to prevent typos. We want our data to be as clean as possible.
Combo boxes are also a great way to control user's input by narrowing down the options a user can use, to the ones we know are correct.
The time and date pickers are another way of preventing "free text" that might make no sense, as we want specifically time and date types of data.
Finally, although not a validation item, you can lower the chances of a user entering typos by enabling the spell check option on textboxes. Just do:
$SomeTextBox.SpellCheck.IsEnabled = $true
Notes about Example9b:
The DatePicker control takes the date format from Window's culture property. If it's different than the format you want on your app, there is a function in the common file that I'm actually using on Example9b. look at the top part of example9b.ps1 file and find it.
Take a close look at the code that executes when a user clicks the Apply button. It's the $Car_Reg_Form_Btn_Apply.add_Click event. Look at how I've implemented the full scan of all relevant controls.
For the TextBox controls, you will need to put Text="{Binding txt}" in their Xaml code. It is what the validation function expects to find. Look at the comments in the function for other types of controls.
Note that you can inform the user that a field is mandatory or to guide him on how to fill the field by either writing it in a Xaml attribute: materialDesign:HintAssist.HelperText like in almost all of the mandatory fields in example9b, or by writing a suffix such as materialDesign:TextFieldAssist.SuffixText="*" like in the license plate TextBox.
Challenge yourself: Write an input validation for the Registration date, that will put a validation error when a user picks a future date (later than today's date).
Comments