How to define textbox input restrictions?

How can I restrict a TextBox to accept only capital letters or, for example, numbers, or prevent a special character from being placed?

Assure that a piece of cake catches the TextInput event and process the text here, but is this the right way to do this?

+54
wpf wpf-controls textbox mask
Jul 09 '09 at 13:06
source share
6 answers

I have done this in the past with attached behavior that can be used as follows:

<TextBox b:Masking.Mask="^\p{Lu}*$"/> 

The attached behavior code is as follows:

 /// <summary> /// Provides masking behavior for any <see cref="TextBox"/>. /// </summary> public static class Masking { private static readonly DependencyPropertyKey _maskExpressionPropertyKey = DependencyProperty.RegisterAttachedReadOnly("MaskExpression", typeof(Regex), typeof(Masking), new FrameworkPropertyMetadata()); /// <summary> /// Identifies the <see cref="Mask"/> dependency property. /// </summary> public static readonly DependencyProperty MaskProperty = DependencyProperty.RegisterAttached("Mask", typeof(string), typeof(Masking), new FrameworkPropertyMetadata(OnMaskChanged)); /// <summary> /// Identifies the <see cref="MaskExpression"/> dependency property. /// </summary> public static readonly DependencyProperty MaskExpressionProperty = _maskExpressionPropertyKey.DependencyProperty; /// <summary> /// Gets the mask for a given <see cref="TextBox"/>. /// </summary> /// <param name="textBox"> /// The <see cref="TextBox"/> whose mask is to be retrieved. /// </param> /// <returns> /// The mask, or <see langword="null"/> if no mask has been set. /// </returns> public static string GetMask(TextBox textBox) { if (textBox == null) { throw new ArgumentNullException("textBox"); } return textBox.GetValue(MaskProperty) as string; } /// <summary> /// Sets the mask for a given <see cref="TextBox"/>. /// </summary> /// <param name="textBox"> /// The <see cref="TextBox"/> whose mask is to be set. /// </param> /// <param name="mask"> /// The mask to set, or <see langword="null"/> to remove any existing mask from <paramref name="textBox"/>. /// </param> public static void SetMask(TextBox textBox, string mask) { if (textBox == null) { throw new ArgumentNullException("textBox"); } textBox.SetValue(MaskProperty, mask); } /// <summary> /// Gets the mask expression for the <see cref="TextBox"/>. /// </summary> /// <remarks> /// This method can be used to retrieve the actual <see cref="Regex"/> instance created as a result of setting the mask on a <see cref="TextBox"/>. /// </remarks> /// <param name="textBox"> /// The <see cref="TextBox"/> whose mask expression is to be retrieved. /// </param> /// <returns> /// The mask expression as an instance of <see cref="Regex"/>, or <see langword="null"/> if no mask has been applied to <paramref name="textBox"/>. /// </returns> public static Regex GetMaskExpression(TextBox textBox) { if (textBox == null) { throw new ArgumentNullException("textBox"); } return textBox.GetValue(MaskExpressionProperty) as Regex; } private static void SetMaskExpression(TextBox textBox, Regex regex) { textBox.SetValue(_maskExpressionPropertyKey, regex); } private static void OnMaskChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e) { var textBox = dependencyObject as TextBox; var mask = e.NewValue as string; textBox.PreviewTextInput -= textBox_PreviewTextInput; textBox.PreviewKeyDown -= textBox_PreviewKeyDown; DataObject.RemovePastingHandler(textBox, Pasting); if (mask == null) { textBox.ClearValue(MaskProperty); textBox.ClearValue(MaskExpressionProperty); } else { textBox.SetValue(MaskProperty, mask); SetMaskExpression(textBox, new Regex(mask, RegexOptions.Compiled | RegexOptions.IgnorePatternWhitespace)); textBox.PreviewTextInput += textBox_PreviewTextInput; textBox.PreviewKeyDown += textBox_PreviewKeyDown; DataObject.AddPastingHandler(textBox, Pasting); } } private static void textBox_PreviewTextInput(object sender, TextCompositionEventArgs e) { var textBox = sender as TextBox; var maskExpression = GetMaskExpression(textBox); if (maskExpression == null) { return; } var proposedText = GetProposedText(textBox, e.Text); if (!maskExpression.IsMatch(proposedText)) { e.Handled = true; } } private static void textBox_PreviewKeyDown(object sender, KeyEventArgs e) { var textBox = sender as TextBox; var maskExpression = GetMaskExpression(textBox); if (maskExpression == null) { return; } //pressing space doesn't raise PreviewTextInput - no idea why, but we need to handle //explicitly here if (e.Key == Key.Space) { var proposedText = GetProposedText(textBox, " "); if (!maskExpression.IsMatch(proposedText)) { e.Handled = true; } } } private static void Pasting(object sender, DataObjectPastingEventArgs e) { var textBox = sender as TextBox; var maskExpression = GetMaskExpression(textBox); if (maskExpression == null) { return; } if (e.DataObject.GetDataPresent(typeof(string))) { var pastedText = e.DataObject.GetData(typeof(string)) as string; var proposedText = GetProposedText(textBox, pastedText); if (!maskExpression.IsMatch(proposedText)) { e.CancelCommand(); } } else { e.CancelCommand(); } } private static string GetProposedText(TextBox textBox, string newText) { var text = textBox.Text; if (textBox.SelectionStart != -1) { text = text.Remove(textBox.SelectionStart, textBox.SelectionLength); } text = text.Insert(textBox.CaretIndex, newText); return text; } } 
+115
Jul 09 '09 at 13:13
source share

I improved Kent Boogaart's answer by following these steps, which previously might have led to a template violation:

  • Backspace
  • Selecting and dragging text in a way that might break the pattern
  • Cut team

For example, Kent Boogaart's answer allowed the user to type “ac” by first typing “abc” and then deleting “b” with backspace that violates the following regular expression

 ^(a|ab|abc)$ 

Usage (no change):

<TextBox b:Masking.Mask="^\p{Lu}*$"/>

Mask class:

 public static class Masking { private static readonly DependencyPropertyKey _maskExpressionPropertyKey = DependencyProperty.RegisterAttachedReadOnly("MaskExpression", typeof(Regex), typeof(Masking), new FrameworkPropertyMetadata()); /// <summary> /// Identifies the <see cref="Mask"/> dependency property. /// </summary> public static readonly DependencyProperty MaskProperty = DependencyProperty.RegisterAttached("Mask", typeof(string), typeof(Masking), new FrameworkPropertyMetadata(OnMaskChanged)); /// <summary> /// Identifies the <see cref="MaskExpression"/> dependency property. /// </summary> public static readonly DependencyProperty MaskExpressionProperty = _maskExpressionPropertyKey.DependencyProperty; /// <summary> /// Gets the mask for a given <see cref="TextBox"/>. /// </summary> /// <param name="textBox"> /// The <see cref="TextBox"/> whose mask is to be retrieved. /// </param> /// <returns> /// The mask, or <see langword="null"/> if no mask has been set. /// </returns> public static string GetMask(TextBox textBox) { if (textBox == null) { throw new ArgumentNullException("textBox"); } return textBox.GetValue(MaskProperty) as string; } /// <summary> /// Sets the mask for a given <see cref="TextBox"/>. /// </summary> /// <param name="textBox"> /// The <see cref="TextBox"/> whose mask is to be set. /// </param> /// <param name="mask"> /// The mask to set, or <see langword="null"/> to remove any existing mask from <paramref name="textBox"/>. /// </param> public static void SetMask(TextBox textBox, string mask) { if (textBox == null) { throw new ArgumentNullException("textBox"); } textBox.SetValue(MaskProperty, mask); } /// <summary> /// Gets the mask expression for the <see cref="TextBox"/>. /// </summary> /// <remarks> /// This method can be used to retrieve the actual <see cref="Regex"/> instance created as a result of setting the mask on a <see cref="TextBox"/>. /// </remarks> /// <param name="textBox"> /// The <see cref="TextBox"/> whose mask expression is to be retrieved. /// </param> /// <returns> /// The mask expression as an instance of <see cref="Regex"/>, or <see langword="null"/> if no mask has been applied to <paramref name="textBox"/>. /// </returns> public static Regex GetMaskExpression(TextBox textBox) { if (textBox == null) { throw new ArgumentNullException("textBox"); } return textBox.GetValue(MaskExpressionProperty) as Regex; } private static void SetMaskExpression(TextBox textBox, Regex regex) { textBox.SetValue(_maskExpressionPropertyKey, regex); } private static void OnMaskChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e) { var textBox = dependencyObject as TextBox; var mask = e.NewValue as string; textBox.PreviewTextInput -= textBox_PreviewTextInput; textBox.PreviewKeyDown -= textBox_PreviewKeyDown; DataObject.RemovePastingHandler(textBox, Pasting); DataObject.RemoveCopyingHandler(textBox, NoDragCopy); CommandManager.RemovePreviewExecutedHandler(textBox, NoCutting); if (mask == null) { textBox.ClearValue(MaskProperty); textBox.ClearValue(MaskExpressionProperty); } else { textBox.SetValue(MaskProperty, mask); SetMaskExpression(textBox, new Regex(mask, RegexOptions.Compiled | RegexOptions.IgnorePatternWhitespace)); textBox.PreviewTextInput += textBox_PreviewTextInput; textBox.PreviewKeyDown += textBox_PreviewKeyDown; DataObject.AddPastingHandler(textBox, Pasting); DataObject.AddCopyingHandler(textBox, NoDragCopy); CommandManager.AddPreviewExecutedHandler(textBox, NoCutting); } } private static void NoCutting(object sender, ExecutedRoutedEventArgs e) { if(e.Command == ApplicationCommands.Cut) { e.Handled = true; } } private static void NoDragCopy(object sender, DataObjectCopyingEventArgs e) { if (e.IsDragDrop) { e.CancelCommand(); } } private static void textBox_PreviewTextInput(object sender, TextCompositionEventArgs e) { var textBox = sender as TextBox; var maskExpression = GetMaskExpression(textBox); if (maskExpression == null) { return; } var proposedText = GetProposedText(textBox, e.Text); if (!maskExpression.IsMatch(proposedText)) { e.Handled = true; } } private static void textBox_PreviewKeyDown(object sender, KeyEventArgs e) { var textBox = sender as TextBox; var maskExpression = GetMaskExpression(textBox); if (maskExpression == null) { return; } string proposedText = null; //pressing space doesn't raise PreviewTextInput, reasons here http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/446ec083-04c8-43f2-89dc-1e2521a31f6b?prof=required if (e.Key == Key.Space) { proposedText = GetProposedText(textBox, " "); } // Same story with backspace else if(e.Key == Key.Back) { proposedText = GetProposedTextBackspace(textBox); } if (proposedText != null && proposedText != string.Empty && !maskExpression.IsMatch(proposedText)) { e.Handled = true; } } private static void Pasting(object sender, DataObjectPastingEventArgs e) { var textBox = sender as TextBox; var maskExpression = GetMaskExpression(textBox); if (maskExpression == null) { return; } if (e.DataObject.GetDataPresent(typeof(string))) { var pastedText = e.DataObject.GetData(typeof(string)) as string; var proposedText = GetProposedText(textBox, pastedText); if (!maskExpression.IsMatch(proposedText)) { e.CancelCommand(); } } else { e.CancelCommand(); } } private static string GetProposedTextBackspace(TextBox textBox) { var text = GetTextWithSelectionRemoved(textBox); if (textBox.SelectionStart > 0 && textBox.SelectionLength == 0) { text = text.Remove(textBox.SelectionStart-1, 1); } return text; } private static string GetProposedText(TextBox textBox, string newText) { var text = GetTextWithSelectionRemoved(textBox); text = text.Insert(textBox.CaretIndex, newText); return text; } private static string GetTextWithSelectionRemoved(TextBox textBox) { var text = textBox.Text; if (textBox.SelectionStart != -1) { text = text.Remove(textBox.SelectionStart, textBox.SelectionLength); } return text; } } 
+44
Sep 27 '11 at 17:00
source share

I changed the VitalyB code to support color themes. Instead of blocking user input, if it does not match the RegEx script, it just highlights the text field. The text box will be the default theme without interaction, and then by default it will be light green or red depending on the value after input. You can also programmatically set the colors for failure and skipping:

 b:ColorMasking.PassColor = "Hexadecimal Value" b:ColorMasking.FailColor = "Hexadecimal Value" 

Class below:

 public class ColorMasking : DependencyObject { private static readonly DependencyPropertyKey _maskExpressionPropertyKey = DependencyProperty.RegisterAttachedReadOnly("MaskExpression", typeof(Regex), typeof(ColorMasking), new FrameworkPropertyMetadata()); /// <summary> /// Identifies the <see cref="Mask"/> dependency property. /// </summary> /// public static readonly DependencyProperty PassColorProperty = DependencyProperty.RegisterAttached("PassColor", typeof(string), typeof(ColorMasking), new PropertyMetadata("#99FF99")); public static void SetPassColor(DependencyObject obj, string passColor) { obj.SetValue(PassColorProperty, passColor); } public static string GetPassColor(DependencyObject obj) { return (string)obj.GetValue(PassColorProperty); } public static readonly DependencyProperty FailColorProperty = DependencyProperty.RegisterAttached("FailColor", typeof(string), typeof(ColorMasking), new PropertyMetadata("#FFCCFF")); public static void SetFailColor(DependencyObject obj, string failColor) { obj.SetValue(FailColorProperty, failColor); } public static string GetFailColor(DependencyObject obj) { return (string)obj.GetValue(FailColorProperty); } public static readonly DependencyProperty MaskProperty = DependencyProperty.RegisterAttached("Mask", typeof(string), typeof(ColorMasking), new FrameworkPropertyMetadata(OnMaskChanged)); private static void OnPassColorChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e) { var textBox = dependencyObject as TextBox; var color = e.NewValue as string; textBox.SetValue(PassColorProperty, color); } /// <summary> /// Identifies the <see cref="MaskExpression"/> dependency property. /// </summary> public static readonly DependencyProperty MaskExpressionProperty = _maskExpressionPropertyKey.DependencyProperty; /// <summary> /// Gets the mask for a given <see cref="TextBox"/>. /// </summary> /// <param name="textBox"> /// The <see cref="TextBox"/> whose mask is to be retrieved. /// </param> /// <returns> /// The mask, or <see langword="null"/> if no mask has been set. /// </returns> public static string GetMask(TextBox textBox) { if (textBox == null) { throw new ArgumentNullException("textBox"); } return textBox.GetValue(MaskProperty) as string; } /// <summary> /// Sets the mask for a given <see cref="TextBox"/>. /// </summary> /// <param name="textBox"> /// The <see cref="TextBox"/> whose mask is to be set. /// </param> /// <param name="mask"> /// The mask to set, or <see langword="null"/> to remove any existing mask from <paramref name="textBox"/>. /// </param> public static void SetMask(TextBox textBox, string mask) { if (textBox == null) { throw new ArgumentNullException("textBox"); } textBox.SetValue(MaskProperty, mask); } /// <summary> /// Gets the mask expression for the <see cref="TextBox"/>. /// </summary> /// <remarks> /// This method can be used to retrieve the actual <see cref="Regex"/> instance created as a result of setting the mask on a <see cref="TextBox"/>. /// </remarks> /// <param name="textBox"> /// The <see cref="TextBox"/> whose mask expression is to be retrieved. /// </param> /// <returns> /// The mask expression as an instance of <see cref="Regex"/>, or <see langword="null"/> if no mask has been applied to <paramref name="textBox"/>. /// </returns> public static Regex GetMaskExpression(TextBox textBox) { if (textBox == null) { throw new ArgumentNullException("textBox"); } return textBox.GetValue(MaskExpressionProperty) as Regex; } private static void SetMaskExpression(TextBox textBox, Regex regex) { textBox.SetValue(_maskExpressionPropertyKey, regex); } private static void OnMaskChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e) { var textBox = dependencyObject as TextBox; var mask = e.NewValue as string; textBox.PreviewTextInput -= textBox_PreviewTextInput; textBox.PreviewKeyDown -= textBox_PreviewKeyDown; DataObject.RemovePastingHandler(textBox, Pasting); DataObject.RemoveCopyingHandler(textBox, NoDragCopy); CommandManager.RemovePreviewExecutedHandler(textBox, NoCutting); if (mask == null) { textBox.ClearValue(MaskProperty); textBox.ClearValue(MaskExpressionProperty); } else { textBox.SetValue(MaskProperty, mask); SetMaskExpression(textBox, new Regex(mask, RegexOptions.Compiled | RegexOptions.IgnorePatternWhitespace)); textBox.PreviewTextInput += textBox_PreviewTextInput; textBox.PreviewKeyDown += textBox_PreviewKeyDown; DataObject.AddPastingHandler(textBox, Pasting); DataObject.AddCopyingHandler(textBox, NoDragCopy); CommandManager.AddPreviewExecutedHandler(textBox, NoCutting); } } private static void NoCutting(object sender, ExecutedRoutedEventArgs e) { if (e.Command == ApplicationCommands.Cut) { e.Handled = true; } } private static void NoDragCopy(object sender, DataObjectCopyingEventArgs e) { if (e.IsDragDrop) { e.CancelCommand(); } } private static void textBox_PreviewTextInput(object sender, TextCompositionEventArgs e) { var textBox = sender as TextBox; var maskExpression = GetMaskExpression(textBox); string passHex = (string)textBox.GetValue(PassColorProperty); string failHex = (string)textBox.GetValue(FailColorProperty); Color passColor = Extensions.ToColorFromHex(passHex); Color failColor = Extensions.ToColorFromHex(failHex); if (maskExpression == null) { return; } var proposedText = GetProposedText(textBox, e.Text); if (!maskExpression.IsMatch(proposedText)) { textBox.Background = new SolidColorBrush(failColor); } else { textBox.Background = new SolidColorBrush(passColor); } } private static void textBox_PreviewKeyDown(object sender, KeyEventArgs e) { var textBox = sender as TextBox; var maskExpression = GetMaskExpression(textBox); string passHex = (string)textBox.GetValue(PassColorProperty); string failHex = (string)textBox.GetValue(FailColorProperty); Color passColor = Extensions.ToColorFromHex(passHex); Color failColor = Extensions.ToColorFromHex(failHex); if (maskExpression == null) { return; } string proposedText = null; //pressing space doesn't raise PreviewTextInput, reasons here http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/446ec083-04c8-43f2-89dc-1e2521a31f6b?prof=required if (e.Key == Key.Space) { proposedText = GetProposedText(textBox, " "); } // Same story with backspace else if (e.Key == Key.Back) { proposedText = GetProposedTextBackspace(textBox); } if (proposedText != null && !maskExpression.IsMatch(proposedText)) { textBox.Background = new SolidColorBrush(failColor); } else { textBox.Background = new SolidColorBrush(passColor); } } private static void Pasting(object sender, DataObjectPastingEventArgs e) { TextBox textBox = sender as TextBox; var maskExpression = GetMaskExpression(textBox); string passHex = (string)textBox.GetValue(PassColorProperty); string failHex = (string)textBox.GetValue(FailColorProperty); Color passColor = Extensions.ToColorFromHex(passHex); Color failColor = Extensions.ToColorFromHex(failHex); if (maskExpression == null) { return; } if (e.DataObject.GetDataPresent(typeof(string))) { var pastedText = e.DataObject.GetData(typeof(string)) as string; var proposedText = GetProposedText(textBox, pastedText); if (!maskExpression.IsMatch(proposedText)) { textBox.Background = new SolidColorBrush(failColor); } else { textBox.Background = new SolidColorBrush(passColor); } } else { textBox.Background = new SolidColorBrush(failColor); } } private static string GetProposedTextBackspace(TextBox textBox) { var text = GetTextWithSelectionRemoved(textBox); if (textBox.SelectionStart > 0) { text = text.Remove(textBox.SelectionStart - 1, 1); } return text; } private static string GetProposedText(TextBox textBox, string newText) { var text = GetTextWithSelectionRemoved(textBox); text = text.Insert(textBox.CaretIndex, newText); return text; } private static string GetTextWithSelectionRemoved(TextBox textBox) { var text = textBox.Text; if (textBox.SelectionStart != -1) { text = text.Remove(textBox.SelectionStart, textBox.SelectionLength); } return text; } } 

To run the script, you need a class written by Aaron C described here: Silverlight / WPF sets the hex color color ellipse shown here: http://www.wiredprairie.us/blog/index.php/archives/659

The code below if the website is ever moving:

 public static class Extensions { public static void SetFromHex(this Color c, string hex) { Color c1 = ToColorFromHex(hex); cA = c1.A; cR = c1.R; cG = c1.G; cB = c1.B; } public static Color ToColorFromHex(string hex) { if (string.IsNullOrEmpty(hex)) { throw new ArgumentNullException("hex"); } // remove any "#" characters while (hex.StartsWith("#")) { hex = hex.Substring(1); } int num = 0; // get the number out of the string if (!Int32.TryParse(hex, System.Globalization.NumberStyles.HexNumber, null, out num)) { throw new ArgumentException("Color not in a recognized Hex format."); } int[] pieces = new int[4]; if (hex.Length > 7) { pieces[0] = ((num >> 24) & 0x000000ff); pieces[1] = ((num >> 16) & 0x000000ff); pieces[2] = ((num >> 8) & 0x000000ff); pieces[3] = (num & 0x000000ff); } else if (hex.Length > 5) { pieces[0] = 255; pieces[1] = ((num >> 16) & 0x000000ff); pieces[2] = ((num >> 8) & 0x000000ff); pieces[3] = (num & 0x000000ff); } else if (hex.Length == 3) { pieces[0] = 255; pieces[1] = ((num >> 8) & 0x0000000f); pieces[1] += pieces[1] * 16; pieces[2] = ((num >> 4) & 0x000000f); pieces[2] += pieces[2] * 16; pieces[3] = (num & 0x000000f); pieces[3] += pieces[3] * 16; } return Color.FromArgb((byte)pieces[0], (byte)pieces[1], (byte)pieces[2], (byte)pieces[3]); } } 
+13
May 25 '12 at 18:53
source share
 private void TextBox1_SelectionChanged(object sender, RoutedEventArgs e) { string txt = TextBox1.Text; if (txt != "") { TextBox1.Text = Regex.Replace(TextBox1.Text, "[^0-9]", ""); if (txt != TextBox1.Text) { TextBox1.Select(TextBox1.Text.Length, 0); } } } 
+2
Mar 10 2018-11-11T00:
source share

Here is another version of existing solutions here. This behavior mimics the TextChanging event, providing old text, new text and a flag to discard the change. Thus, we can implement any filter that we want.

I got rid of the PreviewKeyDown handler, used only for space. It seems that TextBox manages everything with the help of redirected commands, and "Space" has its own command, although it is not publicly available. I also added support for additional keyboard shortcuts, such as "Ctrl + Backspace" (delete the previous word).

 public class TextChangingBehavior : Behavior<TextBox> { public event EventHandler<TextChangingEventArgs> TextChanging; protected override void OnAttached() { base.OnAttached(); AssociatedObject.PreviewTextInput += OnPreviewTextInput; CommandManager.AddPreviewExecutedHandler(AssociatedObject, OnPreviewExecutedHandler); DataObject.AddCopyingHandler(AssociatedObject, OnCopying); DataObject.AddPastingHandler(AssociatedObject, OnPasting); } protected override void OnDetaching() { base.OnDetaching(); AssociatedObject.PreviewTextInput -= OnPreviewTextInput; CommandManager.RemovePreviewExecutedHandler(AssociatedObject, OnPreviewExecutedHandler); DataObject.RemoveCopyingHandler(AssociatedObject, OnCopying); DataObject.RemovePastingHandler(AssociatedObject, OnPasting); } #region Text private enum CharCategory { LetterOrDigit, Whitespace, Other } private CharCategory GetCharCategory(char c) { if (char.IsLetterOrDigit(c)) return CharCategory.LetterOrDigit; else if (char.IsWhiteSpace(c)) return CharCategory.Whitespace; else return CharCategory.Other; } private string GetText(string input = null) { var box = AssociatedObject; var text = box.Text ?? string.Empty; if (input != null) { // Delete selection var deleteCount = box.SelectionLength; if (deleteCount > 0) text = text.Remove(box.SelectionStart, deleteCount); // Insert input if (input.Length > 0) text = text.Insert(box.CaretIndex, input); } return text; } #endregion private void OnPreviewExecutedHandler(object sender, ExecutedRoutedEventArgs e) { var box = AssociatedObject; var selectionExists = box.SelectionLength > 0; var caretIndex = box.CaretIndex; string newText = null; if (e.Command == ApplicationCommands.Cut) { if (selectionExists) newText = GetText(string.Empty); } else if (e.Command == EditingCommands.Backspace) { if (selectionExists) newText = GetText(string.Empty); else if (caretIndex > 0) newText = GetText().Remove(caretIndex - 1, 1); } else if (e.Command == EditingCommands.Delete) { if (selectionExists) newText = GetText(string.Empty); else { newText = GetText(); if (caretIndex >= newText.Length) newText = null; else newText = newText.Remove(caretIndex, 1); } } else if (e.Command == EditingCommands.DeletePreviousWord) { if (selectionExists) newText = GetText(string.Empty); else if (caretIndex > 0) { newText = GetText(); var startIndex = caretIndex; // Include whitespaces do startIndex--; while (startIndex > 0 && char.IsWhiteSpace(newText[startIndex])); // Include the next block var currentCategory = GetCharCategory(newText[startIndex]); while (startIndex > 0 && GetCharCategory(newText[startIndex - 1]) == currentCategory) startIndex--; newText = newText.Remove(startIndex, caretIndex - startIndex); } } else if (e.Command == EditingCommands.DeleteNextWord) { if (selectionExists) newText = GetText(string.Empty); else { newText = GetText(); if (caretIndex >= newText.Length) newText = null; else { var endIndex = caretIndex + 1; // Include the current block var currentCategory = GetCharCategory(newText[caretIndex]); while (endIndex < newText.Length && GetCharCategory(newText[endIndex]) == currentCategory) endIndex++; // Include whitespaces while (endIndex < newText.Length && char.IsWhiteSpace(newText[endIndex])) endIndex++; newText = newText.Remove(caretIndex, endIndex - caretIndex); } } } else if (e.Command is RoutedUICommand cmd && new[] { "Space", "ShiftSpace" }.Contains(cmd.Name)) { newText = GetText(" "); } if (newText != null && OnProcessChange(newText)) e.Handled = true; } private void OnCopying(object sender, DataObjectCopyingEventArgs e) { if (e.IsDragDrop) { if (OnProcessChange(GetText(string.Empty))) e.CancelCommand(); } } private void OnPasting(object sender, DataObjectPastingEventArgs e) { if (e.DataObject.GetDataPresent(typeof(string))) { if (OnProcessChange(GetText((string)e.DataObject.GetData(typeof(string))))) e.CancelCommand(); } } private void OnPreviewTextInput(object sender, TextCompositionEventArgs e) { if (!string.IsNullOrEmpty(e.Text)) { if (OnProcessChange(GetText(e.Text))) e.Handled = true; } } private bool OnProcessChange(string newValue) { var oldValue = GetText(); if (string.Equals(oldValue, newValue, StringComparison.Ordinal)) return false; else { var args = new TextChangingEventArgs(oldValue, newValue); OnTextChanging(args); return args.Cancel; } } protected virtual void OnTextChanging(TextChangingEventArgs e) { TextChanging?.Invoke(this, e); } } public class TextChangingEventArgs : EventArgs { public string OldValue { get; } public string NewValue { get; } public bool Cancel { get; set; } public TextChangingEventArgs(string oldValue, string newValue) { OldValue = oldValue; NewValue = newValue; } } 
0
Apr 25 '19 at 13:03
source share

Another possible solution is to use one of the wpf implementations of "Masked TextBox" using the "MaskedTextProvider" class that is used by "MaskedTextBox" from Winforms.

Two potential solutions are found here → https://wpftoolkit.codeplex.com/wikipage?title=MaskedTextBox and here → http://marlongrech.wordpress.com/2007/10/28/masked-textbox/

-one
Oct. 15 '14 at 15:50
source share



All Articles