这是一个替代方案,只需要一个附加属性和下面的代码。 首先,代码:
public enum InputType
{
PositiveInteger,
PositiveDecimal,
PositiveNullableInteger,
PositiveNullableDecimal,
}
public static class Input
{
public static readonly DependencyProperty TypeProperty =
DependencyProperty.RegisterAttached("Type", typeof(InputType), typeof(TextBox),
new PropertyMetadata(default(InputType), OnTypeChanged));
public static void SetType(TextBox element, InputType value)
{
element.SetValue(TypeProperty, value);
}
public static InputType GetType(TextBox element)
{
return (InputType)element.GetValue(TypeProperty);
}
private class TextSelection
{
public string Text { get; private set; }
public int SelectionStart { get; private set; }
public int SelectionLength { get; private set; }
public TextSelection(string text, int selectionStart, int selectionLength)
{
Text = text;
SelectionStart = selectionStart;
SelectionLength = selectionLength;
}
}
private static readonly DependencyProperty PreviousTextSelectionProperty =
DependencyProperty.RegisterAttached("PreviousTextSelection", typeof(TextSelection),
typeof(TextBox), new PropertyMetadata(default(TextSelection)));
private static void SetPreviousTextSelection(TextBox element, TextSelection value)
{
element.SetValue(PreviousTextSelectionProperty, value);
}
private static TextSelection GetPreviousTextSelection(TextBox element)
{
return (TextSelection)element.GetValue(PreviousTextSelectionProperty);
}
private static void OnTypeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (UIApplication.DesignMode)
return;
var textBox = (TextBox)d;
textBox.TextChanged += OnTextChanged;
textBox.SelectionChanged += OnSelectionChanged;
}
/// <summary>
/// Determines whether the specified text is valid.
/// </summary>
/// <param name="text">The text.</param>
/// <param name="inputType">Type of the input.</param>
/// <returns>
/// <c>true</c> if the specified text is valid; otherwise, <c>false</c>.
/// </returns>
private static bool IsValid(string text, InputType inputType)
{
switch (inputType)
{
case InputType.PositiveInteger:
int i;
return int.TryParse(text, out i);
case InputType.PositiveDecimal:
decimal d;
return decimal.TryParse(text, out d) && d >= 0;
case InputType.PositiveNullableInteger:
return text.IsNullOrEmpty() || IsValid(text, InputType.PositiveInteger);
case InputType.PositiveNullableDecimal:
return text.IsNullOrEmpty() || IsValid(text, InputType.PositiveDecimal);
default:
throw new ArgumentOutOfRangeException("inputType");
}
}
private static void OnTextChanged(object sender, TextChangedEventArgs e)
{
var textBox = (TextBox)sender;
var inputType = GetType(textBox);
if (IsValid(textBox.Text, inputType))
{
SetPreviousTextSelection(textBox, new TextSelection(textBox.Text, textBox.SelectionStart, textBox.SelectionLength));
}
else
{
var textSelection = GetPreviousTextSelection(textBox);
if (textSelection == null)
{
textBox.Text = "";
}
else
{
textBox.Text = textSelection.Text;
textBox.SelectionStart = textSelection.SelectionStart;
textBox.SelectionLength = textSelection.SelectionLength;
}
}
}
private static void OnSelectionChanged(object sender, RoutedEventArgs e)
{
var textBox = (TextBox)sender;
SetPreviousTextSelection(textBox, new TextSelection(textBox.Text, textBox.SelectionStart, textBox.SelectionLength));
}
}
然后在你的XAML代码使用它(“UI”名称空间要求解决,但是,嘿,你还要做您的家庭作业:)):
<TextBox Text="{Binding MyText, Mode=TwoWay}" ui:Input.Type="PositiveNullableDecimal" />
所以基本上,扩展器会记住最后一个有效状态(文本+选择),并在新结果无效时恢复它。 enum InputType当然可以扩展。
这很危险,因为它假设一个数字是用“ - ”和数字在“0”和“9”之间写的,这对所有的文化来说都是不正确的。你也必须处理关键和文本事件,所以这是最低工作的两倍:) 我在下面发布了一个替代方案。 – picrap 2012-03-26 17:01:12