如何定义TextBoxinput限制?

如何限制TextBox只接受大写字母或数字,或禁止放置任何特殊字符?

当然,抓住TextInput事件并处理这里的文本是一块蛋糕,但这是否是正确的方法呢?

过去我已经做了一个附加的行为,可以这样使用:

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

附加的行为代码如下所示:

 /// <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; } } 

我已经改进了Kent Boogaart的回答,还处理了以前可能导致违反该模式的以下行为:

  • 退格
  • select和拖动文本的方式可能会违反该模式
  • 剪切命令

例如,Kent Boogaart的回答允许用户通过首先input“abc”来input“ac”,然后删除具有违反以下正则expression式的退格的“b”

 ^(a|ab|abc)$ 

用法(不变):

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

面膜类:

 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; } } 

我改变了VitalyB的代码来支持颜色主题。 它不会阻止用户input,如果它不符合RegEx脚本,它只是突出显示文本框。 文本框将成为没有交互的主题默认,然后根据input设置后的值默认为浅绿色或红色。 您还可以设置失败并以编程方式传递颜色:

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

class级如下:

 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; } } 

要运行,脚本需要Aaron C编写的类,在这里解释: Silverlight / WPF设置椭圆hex颜色显示在这里: http : //www.wiredprairie.us/blog/index.php/archives/659

下面的代码是为了防止网站被移动:

 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]); } } 
 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); } } } 

另一种可能的解决scheme是使用Winforms中“MaskedTextBox”使用的“MaskedTextProvider”类的“Masked TextBox”wpf实现之一。

这里find两个可能的解决scheme – > https://wpftoolkit.codeplex.com/wikipage?title=MaskedTextBox ,在这里 – > http://marlongrech.wordpress.com/2007/10/28/masked-textbox/