Description
When working with input data (TextBox) you will usually have a certain data type that you expect from the end user. This may be an integer or string type. Even if it’s a string then you may want to check if it matches a certain pattern.
You can of course use a validation and that will simply color in red the faulty lines but that was not what I was looking for, I needed something that will not allow the user to insert a string in a number field.
There is a nice library (Interactivity) where you can define behaviours, but I was creating an add-in and this proved to be a problem, so I decided to make something simple but pretty powerfull. Of course you may extend it as you like:
Solution
public class TextboxStrict { private Regex validate; private string lastKnowText = ""; private string defaultText = ""; private int defaultCaretIndex = 0; private int lastKnownCaretIndex = 0; /// inputChange - marks that the change was made by this class so that /// when text changed is fired again - caret index will not move it's position private bool inputChange = false; public TextboxStrict(string regexPattern, string startWith = "") { validate = new Regex(regexPattern); ///lastKnownText will be the placeholder of any good changes in text status this.lastKnowText = startWith; ///default text will be the holder of the default text on initialize and on text == "" this.defaultText = startWith; this.lastKnownCaretIndex = startWith.Length; this.defaultCaretIndex = startWith.Length; } public void AttachTo(TextBox textBox) { ///Initializing text box data with default entries textBox.Text = this.defaultText; textBox.CaretIndex = this.defaultCaretIndex; textBox.TextChanged += EvtTextChanged; textBox.SelectionChanged += EvtSelectionChanged; } /// <summary> /// Validate function /// </summary> private bool Validate(string text) { return validate.IsMatch(text); } /// <summary> /// Making sure last known caret index keeps track /// </summary> private void EvtSelectionChanged(object sender, RoutedEventArgs e) { TextBox textBox = (TextBox)sender; lastKnownCaretIndex = textBox.CaretIndex; } /// <summary> /// Validates text and keeps last known good one. Keeps track of caret index also /// </summary> private void EvtTextChanged(object sender, TextChangedEventArgs e) { TextBox textbox = (TextBox)sender; if (textbox.Text == "") { inputChange = true; textbox.Text = this.defaultText; textbox.CaretIndex = this.defaultCaretIndex; } ///If it doesn't validate - change back. Mark as internal change to not override the last index else if (!this.Validate(textbox.Text)) { inputChange = true; textbox.Text = lastKnowText; textbox.CaretIndex = lastKnownCaretIndex; } else { if (!inputChange) { lastKnowText = textbox.Text; lastKnownCaretIndex = textbox.CaretIndex; } inputChange = false; } } }
Usage
The class above will attach 2 events to the textbox (textchanged and selectionchanged).
public partial class MainWindow : Window { TextboxStrict inputLimit = new TextboxStrict("^[0-9]{1,10}$", "0"); public MainWindow() { InitializeComponent(); inputLimit.AttachTo(TestTextBox); } }