2009-07-09 11 views
52

Comment est-ce que je peux restreindre TextBox pour accepter seulement des lettres majuscules, ou par exemple des chiffres, ou interdire de mettre n'importe quel caractère spécial?Comment définir les restrictions d'entrée TextBox?

Bien sûr, c'est un morceau de gâteau pour attraper l'événement TextInput et gérer le texte ici, mais est-ce la bonne façon de faire cela?

Répondre

110

Je l'ai fait dans le passé avec un comportement attaché, qui peut être utilisé comme ceci:

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

Le code de comportement attaché ressemble à ceci:

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

Wow .. merde .. pourquoi il est si difficile? – Agzam

+0

Je ne dirais pas que c'était. Je l'ai écrit pour être beaucoup plus flexible que nécessaire. N'hésitez pas à prendre le concept et à simplifier pour vos besoins. –

+1

Très bien, Kent. Une solution flexible et puissante pour limiter l'entrée dans un TextBox. +1 –

2
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); 
     } 
    } 
} 
+0

Je ne sais pas comment faire une propriété personnalisée, mais c'est une solution simple. J'apprécierais que quelqu'un le convertisse en propriété comme Kent l'a fait. – WhoIsNinja

43

I a amélioré la réponse de Kent Boogaart en traitant également les actions suivantes qui auparavant pouvaient entraîner la violation du modèle:

  • Backspace
  • Sélection et en faisant glisser le texte d'une manière qui peut violer le modèle
  • Cut commande

Par exemple, la réponse de Kent Boogaart permet à l'utilisateur d'entrer « ac » en entrant d'abord « abc » et supprimer ensuite le "b" avec le backspace qui viole la regex

^(a|ab|abc)$ 

Utilisation (inchangé) suivant:

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

classe Masque:

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

Vous avez amélioré la solution de trois façons, mais la lecture de sa courte description ne vous dit rien. Je pense que cela a à voir avec le collage de texte dans le TextBox, mais la solution de Kent bloquait déjà le texte défectueux. Pouvez-vous expliquer quels cas d'utilisation les améliorations empêchent? Merci – buckley

+0

Ces améliorations empêchent l'utilisateur de violer la règle regex. Par exemple, avant ces modifications, vous pouvez utiliser Backspace pour rendre la règle illégale. Donc, si le motif était '^ 123 $', vous pourriez taper '123', puis supprimer' 2' et vous le laisserait. Maintenant non. Idem pour les autres améliorations - Couper du texte et faire glisser du texte. – VitalyB

+0

Je peux voir ce que vous voulez dire maintenant, mais seule une action de copier-coller peut amener l'utilisateur au point où il y a "123" dans la zone de texte pour commencer. Taper juste le caractère "1" (ou n'importe quel autre caractère) sera impossible car il ne valide pas "^ 123 $". Utiliser backspace sur un * typed * dans une chaîne respectera toujours le motif car l'entrée précédente a déjà été validée. Certains utilisateurs vont certainement copier coller et votre amélioration va aborder ce cas de bord qui aurait été un mystère pendant un certain temps comment cela s'est passé. Merci – buckley

12

J'ai changé le code de VitalyB pour soutenir Thèmes de couleur. Au lieu de bloquer l'entrée de l'utilisateur s'il ne répond pas au script RegEx, il ne fait que mettre en surbrillance la zone de texte. La zone de texte sera le thème par défaut sans interaction, puis sera par défaut une lumière verte ou rouge en fonction de la valeur après que l'entrée est définie. Vous pouvez également définir l'échec et passer des couleurs programatically avec:

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

La classe est ci-dessous:

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

Pour exécuter le script nécessite une classe écrite par Aaron C, a expliqué ici: Silverlight/WPF sets ellipse with hexadecimal colour montré ici : http://www.wiredprairie.us/blog/index.php/archives/659

le code est ci-dessous dans le cas où le site est toujours déplacé:

public static class Extensions 
{ 
    public static void SetFromHex(this Color c, string hex) 
    { 
     Color c1 = ToColorFromHex(hex); 

     c.A = c1.A; 
     c.R = c1.R; 
     c.G = c1.G; 
     c.B = 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]); 
    } 

}