Silverlight numeric textbox?
I tryed to create my own numeric textbox here is my code:
public class NumericTextBox : TextBox
{
public NumericTextBox()
: base()
{
this.Text = "0";
}
private void HandleKeyEvent(KeyEventArgs e)
{
e.Handled = true;
if ((Keyboard.Modifiers & ModifierKeys.Alt) != 0)
{
return;
}
if (e.Key == Key.Back || e.Key == Key.Delete || e.Key == Key.Left || e.Key == Key.Right ||
e.Key == Key.D0 || e.Key == Key.D1 || e.Key == Key.D2 || e.Key == Key.D3 || e.Key == Key.D4 || e.Key == Key.D5 || e.Key == Key.D6 ||
e.Key == Key.D7 || e.Key == Key.D8 || e.Key == Key.D9 ||
e.Key == Key.NumPad0 || e.Key == Key.NumPad1 || e.Key == Key.NumPad2 || e.Key == Key.NumPad3 || e.Key == Key.NumPad4 || e.Key == Key.NumPad5 || e.Key == Key.NumPad6 ||
e.Key == Key.NumPad7 || e.Key == Key.NumPad8 || e.Key == Key.NumPad9)
{
e.Handled = false;
}
else if ((e.Key == Key.Subtract || (e.Key == Key.Unknown && e.PlatformKeyCode == 189)) && b开发者_运维技巧ase.SelectionStart == 0 && (base.Text.Length == 0 || base.Text[0] != '-'))
{
e.Handled = false;
}
}
protected override void OnKeyDown(KeyEventArgs e)
{
HandleKeyEvent(e);
base.OnKeyDown(e);
}
protected override void OnKeyUp(KeyEventArgs e)
{
HandleKeyEvent(e);
base.OnKeyUp(e);
}
}
everything works like supposed but if you press alt and some numbers it creates the ascii symbol corresponding to the number.. is there any way to block an "alt + number combination? it seems that alt + key just gets entered without going threw OnKeyUp or OnKeyDown...
I got it working by using the TextChanged event here is my code...
public class NumericTextBox : TextBox
{
int value;
public NumericTextBox()
: base()
{
this.Text = "0";
this.TextChanged += new TextChangedEventHandler(NumericTextBox_TextChanged);
}
void NumericTextBox_TextChanged(object sender, TextChangedEventArgs e)
{
int selectionStart = base.SelectionStart;
bool changed = false;
List<char> charList = new List<char>();
for (int i = 0; i < base.Text.Length; i++)
{
if (IsValidChar(base.Text[i], i))
{
charList.Add(base.Text[i]);
}
else
{
if (selectionStart >= i)
{
selectionStart--;
}
changed = true;
}
}
if (changed)
{
string text = new string(charList.ToArray());
this.Text = text;
this.SelectionStart = selectionStart;
}
int newValue;
if (!int.TryParse(this.Text, out newValue))
{
this.Text = value.ToString();
this.SelectionStart = this.Text.Length;
}
else
{
value = newValue;
}
}
private bool IsValidChar(char c, int index)
{
return ((c == '-' && index == 0) || c == '0' || c == '1' || c == '2' || c == '3' || c == '4' || c == '5' || c == '6' || c == '7' || c == '8' || c == '9');
}
private void HandleKeyEvent(KeyEventArgs e)
{
e.Handled = true;
if ((Keyboard.Modifiers & ModifierKeys.Control) == ModifierKeys.Control)
{
e.Handled = false;
}
if (e.Key == Key.Back || e.Key == Key.Delete || e.Key == Key.Left || e.Key == Key.Right ||
e.Key == Key.D0 || e.Key == Key.D1 || e.Key == Key.D2 || e.Key == Key.D3 || e.Key == Key.D4 || e.Key == Key.D5 || e.Key == Key.D6 ||
e.Key == Key.D7 || e.Key == Key.D8 || e.Key == Key.D9 ||
e.Key == Key.NumPad0 || e.Key == Key.NumPad1 || e.Key == Key.NumPad2 || e.Key == Key.NumPad3 || e.Key == Key.NumPad4 || e.Key == Key.NumPad5 || e.Key == Key.NumPad6 ||
e.Key == Key.NumPad7 || e.Key == Key.NumPad8 || e.Key == Key.NumPad9)
{
e.Handled = false;
}
else if ((e.Key == Key.Subtract || (e.Key == Key.Unknown && e.PlatformKeyCode == 189)) && base.SelectionStart == 0 && (base.Text.Length == 0 || base.Text[0] != '-'))
{
e.Handled = false;
}
}
protected override void OnKeyDown(KeyEventArgs e)
{
HandleKeyEvent(e);
base.OnKeyDown(e);
}
protected override void OnKeyUp(KeyEventArgs e)
{
HandleKeyEvent(e);
base.OnKeyUp(e);
}
}
Here's an alternative, requiring only an attached property and the following code. First, the code:
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));
}
}
Then use it in your xaml code (the "ui:" namespace requires to be resolved, but hey, you still have to do your homeworks :)):
<TextBox Text="{Binding MyText, Mode=TwoWay}" ui:Input.Type="PositiveNullableDecimal" />
So basically, the extender memorizes the last valid state (text+selection) and reverts it if the new result is invalid. The enum InputType can be of course extended.
is there any way to block an "alt + number combination?
Not really. My advice would be don't bother and see what happens.
TBH if you really want to build a Numeric input control you shouldn't be deriving from TextBox
. You would derive from Control
and place a TextBox in the default control template of your new control.
In fact to be really honest I'd just used the NumericUpDown in the Toolkit.
Are you just trying to prevent non-numeric text entry? A different approach described in this blog post is to create a text box filter that can be added to a normal TextBox as an attached dependency property. Either way, you will still have to validate the data after it is entered as the user could paste invalid data.
Short and sweet - the Alt key is handled at a lower level then your program.
This article describes the problem in more detail while this link provides some c++ code that could help you if you really wanted to get around this issue.
精彩评论