Я изменил код VitalyB для поддержки цветовых тем. Вместо того, чтобы блокировать ввод пользователя, если он не соответствует сценарию RegEx, он просто выделяет текстовое поле. Текстовое поле будет темой по умолчанию без взаимодействия, а затем по умолчанию будет светло-зеленым или красным в зависимости от значения после установки ввода. Вы также можете установить сбой и передать цвета программно с помощью:
b:ColorMasking.PassColor = "Hexadecimal Value"
b:ColorMasking.FailColor = "Hexadecimal Value"
Класс ниже:
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;
}
}
Для запуска сценария требуется класс, написанный Аароном Си, объясненный здесь: Silverlight / WPF устанавливает эллипс с шестнадцатеричным цветом , показанным здесь: 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);
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]);
}
}