這是一個替代方案,只需要一個附加屬性和下面的代碼。 首先,代碼:
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