Creating custom User Controls (WPF)
In this tutorial we'll program MaskedTextBox in WPF and show how to include a control in the application using code and XAML.
Creating a control
Our MaskedTextBox will work similarly to how it works in Windows Forms. Thus, it'll have a mask property into which the verified format will be inserted. Our version will be simple, it'll only support numbers, letters and a decimal point for the example. We'll control them by their ASCII code, which can be found in the ASCII table below. Here I listed the codes of characters that we'll need:
Let's start by creating a new WPF project. In the Solution explorer window, right-click on the application's project, select Add > New Item from the context menu. Move to WPF and select User Control. Let's name it MaskedTextBox.
Char | ASCII |
---|---|
a-z | 97-122 |
A-Z | 65-90 |
. | 46 |
, | 44 |
Our created control will be included in the Toolbox window. Notice that the control has the .xaml extension and its code .cs (vb). Let's open the XAML Designer and add a plain TextBox. We'll name it generalTextBox. Set the main grids' height to 20 and the width to 200. Now we have UI of our custom control done.
Go to the code editor of our control, add the following properties there:
private BadValueHandler _valueHandler; public BadValueHandler valueHandler { get { return _valueHandler; } set { _valueHandler = value; } } private string _mask; public string mask { get { return _mask; } set { System.Collections.Generic.List<string> charArray = new System.Collections.Generic.List<string>(); for (int i = 0; i < value.Length; i++) { charArray.Add(value.Substring(i, 1)); } foreach (var character in charArray) { switch (character) { case "0": break; case "a": break; case ".": break; default: throw new FormatException("Invalid character in the mask"); } } _mask = value; } } public string Text { get { return generalTextBox.Text; } set { generalTextBox.Text = value; } }
We use the mask property to validate the entered value. Next we have the valueHandler property of the type BadValueHandler, which we'll add in a while.
Add a new BadValueHandler enumeration to the code:
public enum BadValueHandler { RedBox, MessageBox }
This is there for a reason. The value will determine how the program behaves when the user enters invalid text, i.e. text that isn't in the mask's format. The behavior for each value is in the table below:
Value | Behaviour |
---|---|
RedBox | A text box turns red. |
MessageBox | A message dialog box appears to the user. |
In the XAML code for the generalTextBox control, create a TextChanged event handler. Navigate to the code editor. Create a private function Validate(), which will return a value of the type bool (boolean). Paste the following code into this function:
string writedText = generalTextBox.Text; string mask = this.mask; if (writedText.Length != mask.Length) { return false; } for (int i = 0; i < mask.Length; i++) { string maskChar = mask.Substring(i, 1); string charInArray = writedText.Substring(i, 1); switch (maskChar) { case "0": try { Int testValue = int.Parse(charInArray) / 2; } catch (Exception) { return false; } break; case "a": int asc = (int)char.Parse(charInArray); if (!((asc >= 65 && asc <= 90) || (asc >= 97 && asc <= 122))) { return false; } break; case ".": int dotAsc = (int)char.Parse(charInArray); if (!(dotAsc == 46 || dotAsc == 44)) { return false; } break; default: throw new FormatException("Invalid mask format"); } } return true;
This function goes through all characters of the mask according to the mask. At the beginning, it checks whether the entered text is the same length as the mask. If not, then logically the text cannot have the correct format, because it either has extra characters or some characters are missing. Then it goes through individual characters in the mask, according to them it's being verified if it's the number s trying to divide. If it's not possible, it throws an exception and the entered text is invalid. When it's a letter, ASCII is being verified, as well as a decimal point and a comma. If there is a character other than a supported character in the mask (there should no longer be at this point, but just to be safe), the FormatException exception is thrown and the text "Invalid mask format" is passed to it as a message. Now back to the TextChanged event handler, paste the following code into it:
if (validate()) { generalTextBox.Background = Brushes.White; } else { switch (valueHandler) { case BadValueHandler.RedBox: generalTextBox.Background = Brushes.OrangeRed; break; case BadValueHandler.MessageBox: if (mask.Length == generalTextBox.Text.Length) { MessageBox.Show("You've entered an invalid value, enter a value in the format: " + mask, "Invalid value", MessageBoxButton.OK, MessageBoxImage.Warning); } break; } }
As you can see, here we verify that it's valid. If so, we set the background color to white, because if the user enters an invalid value (red) and only then the correct one, the color returns to white. If the entered text isn't valid, the value in the ValueHandler is verified (the type of this value is the BadValueHandler enumeration). If the value is RedBox then the field turns red (red is too aggressive, so I chose orange-red). If the value is MessageBox, a warning dialog box will be displayed, but it won't be displayed until the same number of characters are in the mask and in the array. This is because the dialog box shouldn't be displayed during entering, but when the user finishes entering. This way the dialog box would appear after entering every single character.
Implementing a control
In the previous section, we created a control, but how to implement it in a form application?
The advantage of custom controls is also that we can influence how they're displayed. As far as I know, there are two ways to add controls to a form. If you know others, let me know in the discussion below the article.
Implementing using XAML
First click on BUILD > Build Solution to compile the solution. Sometimes there are problems with adding uncompiled controls. Open the XAML Designer and view the Toolbox window. You'll see a new group of controls "<project name> Control". There's also MaskedTextBox (<project name>) Control. Drag this control onto the form. Place it where you want and set it to reasonable size.
Next, set properties it'll need for its own purposes (i.e. the mask and valueHandler properties). Set the Mask property to e.g.: "0000.aaaa". Set the valueHandler property to RedBox. Compile and run the application.
Try entering different values in the text box. You'll see that the text box will be red until you enter a value in the correct format.
Implementing in code
After loading the form, we'll add a second control and test it from the value sanitization using the message dialog box.
Set the Name property of a single grid control to: "mainGrid", we'll add MaskedTextBox to this control. Create a Load event handler to the form. Enter the following code in it, or add properties for the size and location:
textb.mask = "aaaa.0000"; textb.Width = 150; textb.valueHandler = MaskedTextBox.BadValueHandler.MessageBox; mainGrid.Children.Add(textb);
Now run the application, try entering values. Once you enter the correct number of characters, it'll verify that they are correct. If so, nothing will happen. If not, the warning dialog box will appear.
Download
By downloading the following file, you agree to the license terms
Downloaded 8x (110.87 kB)
Application includes source codes in language C#