How to create a numeric textbox in Silverlight?
Asked Answered
E

11

12

As the title says really. I've had a look at inheriting from TextBox, but the only sensible override was "OnKeyDown", but that just gives me a key from the Key enum (with no way to use Char.IsNumeric()).

Electrode answered 6/11, 2008 at 10:19 Comment(0)
O
5

Take a look at NumericUpDown in the Toolkit http://codeplex.com/Silverlight and maybe you can use that or look at the source to implement your own numeric textbox.

Ormuz answered 6/11, 2008 at 13:36 Comment(2)
There is only one problem with NumericUpDown. For example you have the value 999 in it and you use backspace to clear the input, then you lose focus and it sets 999 back again instead of seting it to 0.Catalano
Why do you think it is a problem? =))Transcendentalistic
I
9

I took Nidhal's suggested answer and edited it a bit to handle the shift case for the characters above the digits (ie. !@#$%^&*()) since that solution will still allow those characters in the textbox.

private void NumClient_KeyDown(object sender, KeyEventArgs e)
{       
    // Handle Shift case
    if (Keyboard.Modifiers == ModifierKeys.Shift)
    {
       e.Handled = true;
    }

    // Handle all other cases
    if (!e.Handled && (e.Key < Key.D0 || e.Key > Key.D9))
    {
        if (e.Key < Key.NumPad0 || e.Key > Key.NumPad9)
        {
            if (e.Key != Key.Back)
            {
                e.Handled = true;
            }
        }
    }           
}
Incalescent answered 4/11, 2010 at 15:25 Comment(2)
This swallows the TAB and shift-Tab key as well.Rathenau
how would you do this in MVVM?Bekki
A
7

Visit http://www.dataartist.net/blog/post/Silverlight-Behavior-Modifications-13-NumericOnlyBehavior.aspx or use TextBox behavior as below

  using System;
  using System.Windows;
  using System.Windows.Controls;
  using System.Windows.Input;
  using System.Windows.Interactivity;

  namespace DataArtist
  {
public class NumericOnly : Behavior<TextBox>
{
    private string Text { get; set; }
    private bool shiftKey;
    public bool StripOnExit { get; set; }

    public NumericOnly()
    {
        StripOnExit = false;
    }

    protected override void OnAttached()
    {
        base.OnAttached();
        AssociatedObject.KeyDown += KeyDown;
        AssociatedObject.KeyUp += KeyUp;
        AssociatedObject.GotFocus += GotFocus;
        AssociatedObject.LostFocus += LostFocus;
    }

    void KeyUp(object sender, KeyEventArgs e)
    {
        if (e.Key == Key.Shift)
        {
            shiftKey = false;
        }
    }

    void KeyDown(object sender, KeyEventArgs e)
    {
        if (StripOnExit != false || e.Key == Key.Tab || e.Key == Key.Enter)
        {
            return;
        }

        if (e.Key == Key.Shift)
        {
            shiftKey = true;
        }
        else
        {
            if (IsNumericKey(e.Key) == false)
            {
                e.Handled = true;
            }
        }
    }

    void GotFocus(object sender, RoutedEventArgs e)
    {
        Text = AssociatedObject.Text;
    }

    private void LostFocus(object sender, RoutedEventArgs e)
    {
        if (AssociatedObject.Text == Text)
        {
            return;
        }

        string content = string.Empty;

        foreach (var c in AssociatedObject.Text)
        {
            if (Char.IsNumber(c) == true)
            {
                content += c;
            }
        }

        AssociatedObject.Text = content;
    }

    public bool IsNumericKey(Key key)
    {
        if (shiftKey == true)
        {
            return false;
        }

        string code = key.ToString().Replace("NumPad", "D");

        if (code[0] == 'D' && code.Length > 1)
        {
            return (Char.IsNumber(code[1]));
        }

        return false;
    }

    protected override void OnDetaching()
    {
        base.OnDetaching();
        AssociatedObject.KeyDown -= KeyDown;
        AssociatedObject.LostFocus -= LostFocus;
        AssociatedObject.GotFocus -= GotFocus;
    }
}   
    }
Atomicity answered 5/12, 2011 at 13:3 Comment(1)
A behavior is definitely the way to go. It's also easier to clear out than attached properties. (Attached properties that wire into the KeyUp and KeyDown handlers have a good chance of creating GC roots and preventing garbage collection. The behavior can be modified so all of the event handlers are added in the Loaded event and then unhooked in the Unloaded event.)Eno
T
6
private void Numclient_KeyDown(object sender, KeyEventArgs e)
{
    if (e.Key < Key.D0 || e.Key > Key.D9)
    {
        if (e.Key < Key.NumPad0 || e.Key > Key.NumPad9)
        {
            if (e.Key != Key.Back && e.Key != Key.Shift)
            {
                e.Handled = true;
            }
        }
    }
}
Togliatti answered 28/5, 2010 at 9:7 Comment(1)
amurra's edit is an improvment on this, us it instead: #268707Rathenau
O
5

Take a look at NumericUpDown in the Toolkit http://codeplex.com/Silverlight and maybe you can use that or look at the source to implement your own numeric textbox.

Ormuz answered 6/11, 2008 at 13:36 Comment(2)
There is only one problem with NumericUpDown. For example you have the value 999 in it and you use backspace to clear the input, then you lose focus and it sets 999 back again instead of seting it to 0.Catalano
Why do you think it is a problem? =))Transcendentalistic
G
4

Take a look at this one, it uses an attached property over the textbox. I am using it and it does work. http://weblogs.asp.net/manishdalal/archive/2008/09/24/prevention-the-first-line-of-defense-with-attach-property-pixie-dust.aspx

Geum answered 23/9, 2009 at 23:38 Comment(1)
your link seem to have diedSeine
S
2
    private void TextBox_KeyDown(object sender, KeyEventArgs e)
    {
        bool isDigit = e.Key >= Key.D0 && 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.Key == Key.Back || e.Key == Key.Delete || e.Key == Key.Left || e.Key == Key.Right;

        if (isDigit) { }
        else
            e.Handled = true; 
    }
Singspiel answered 11/12, 2013 at 8:30 Comment(0)
K
1

It works:

static bool AltGrIsPressed;

void Numclient_KeyUp(object sender, KeyEventArgs e)
{
    if (e.Key == Key.Alt)
    {
        AltGrIsPressed = false;
    }
}

void Numclient_KeyDown(object sender, KeyEventArgs e)
{
    if (e.Key == Key.Alt)
    {
        AltGrIsPressed = true;
    }

    if (Keyboard.Modifiers == ModifierKeys.Shift || AltGrIsPressed == true)
    {
        e.Handled = true;
    }

    if (e.Handled == false && (e.Key < Key.D0 || e.Key > Key.D9))
    {
        if (e.Key < Key.NumPad0 || e.Key > Key.NumPad9)
        {
            if (e.Key != Key.Back)
            {
                e.Handled = true;
            }
        }
    }       
}
Kamp answered 21/4, 2011 at 9:3 Comment(0)
H
1
private void txtbox_KeyDown(object sender, KeyEventArgs e)
{
    if (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
        e.Handled = true;
}
Hutchins answered 31/5, 2011 at 11:43 Comment(0)
Q
1

I know it has been answered, but I found no proper solution that handles all special cases, most answers here swallows some important keys like Home, End, Tab, Shift+ any thing, ..etc.

So, I developed my own implementation as it may help somebody!

public class IntegerTextBox : TextBox
    {
        /// <summary>
        /// To be raised whenever integer value changed
        /// </summary>
        public event EventHandler ValueChanged;

        /// <summary>
        /// To restore if the user entered invalid characters
        /// </summary>
        private int lastSavedValue = 0;

        private int lastSelectionStart = 0;
        private int lastSelectionLength = 0;


        public int IntegerValue
        {
            get
            {
                //the default value is 0 if there is no text in the textbox
                int value = 0;
                int.TryParse(Text, out value);
                return value;
            }
            set
            {
                if (this.Text.Trim() != value.ToString())
                {
                    Text = value.ToString();
                }
            }
        }

        public IntegerTextBox()
            : base()
        {
            this.LostFocus += (sender, e) =>
                {
                    //if the user clears the text the text box and leaves it, set it to default value
                    if (string.IsNullOrWhiteSpace(this.Text))
                        IntegerValue = 0;
                };
            this.Loaded += (sender, e) =>
                {
                    //populate the textbox with Initial IntegerValue (default = 0)
                    this.Text = this.IntegerValue.ToString();
                };

            this.TextChanged += (sender, e) =>
                {
                    int newValue = 0;
                    if (int.TryParse(this.Text, out newValue)) //this will handle most cases like number exceeds the int max limits, negative numbers, ...etc.
                    {
                        if (string.IsNullOrWhiteSpace(Text) || lastSavedValue != newValue)
                        {
                            lastSavedValue = newValue;
                            //raise the event
                            EventHandler handler = ValueChanged;
                            if (handler != null)
                                handler(this, EventArgs.Empty);

                        }
                    }
                    else 
                    {
                        //restore previous number
                        this.Text = lastSavedValue.ToString();
                        //restore selected text
                        this.SelectionStart = lastSelectionStart;
                        this.SelectionLength = lastSelectionLength;
                    }
                };

            this.KeyDown += (sender, e) =>
                {
                    //before every key press, save selection start and length to handle overwriting selected numbers
                    lastSelectionStart = this.SelectionStart;
                    lastSelectionLength = this.SelectionLength;
                };
        }
    } 

The above code has a single disadvantage, TextChanged event will be raised frequently, but since we need an integer textbox, then we can rely on ValueChanged instead!

Quoin answered 6/9, 2011 at 11:0 Comment(0)
B
0

Extend the normal Silverlight Textbox control. Add this code inside the extended TextBox class:

string nums = "1234567890";
string lastText = "";
int lastSelStart = 0;

protected override void TextChanged(object sender, TextChangedEventArgs e)
{
    if(!nums.Contains(this.Text.Substring(this.Text.Length -1)))
    {
         this.Text = lastText;
         this.SelectionStart = lastSelStart;
         return;
    }

    lastText = this.Text;
    lastSelStart = this.SelectionStart;

}
Bernini answered 1/9, 2011 at 2:54 Comment(0)
B
-1

Why is everyone not doing the hard work of just handling them all?

Here (this is perfection):

<TextBox KeyDown="TextBox_KeyDown" />

private void TextBox_KeyDown(object sender, KeyEventArgs e)
{
    var _Letter = string.Empty;
    switch (e.Key)
    {
        case Key.A: _Letter = "A"; break;
        case Key.Add: _Letter = "+"; break;
        case Key.Alt: break;
        case Key.B: _Letter = "B"; break;
        case Key.Back: break;
        case Key.C: _Letter = "C"; break;
        case Key.CapsLock: break;
        case Key.Ctrl: break;
        case Key.D: _Letter = "D"; break;
        case Key.D0: _Letter = "0"; break;
        case Key.D1: _Letter = "1"; break;
        case Key.D2: _Letter = "2"; break;
        case Key.D3: _Letter = "3"; break;
        case Key.D4: _Letter = "4"; break;
        case Key.D5: _Letter = "5"; break;
        case Key.D6: _Letter = "6"; break;
        case Key.D7: _Letter = "7"; break;
        case Key.D8: _Letter = "8"; break;
        case Key.D9: _Letter = "9"; break;
        case Key.Decimal: _Letter = "."; break;
        case Key.Delete: break;
        case Key.Divide: _Letter = "/"; break;
        case Key.Down: break;
        case Key.E: _Letter = "E"; break;
        case Key.End: break;
        case Key.Enter: break;
        case Key.Escape: break;
        case Key.F: _Letter = "F"; break;
        case Key.F1: break;
        case Key.F10: break;
        case Key.F11: break;
        case Key.F12: break;
        case Key.F2: break;
        case Key.F3: break;
        case Key.F4: break;
        case Key.F5: break;
        case Key.F6: break;
        case Key.F7: break;
        case Key.F8: break;
        case Key.F9: break;
        case Key.G: _Letter = "G"; break;
        case Key.H: _Letter = "H"; break;
        case Key.Home: break;
        case Key.I: _Letter = "I"; break;
        case Key.Insert: break;
        case Key.J: _Letter = "J"; break;
        case Key.K: _Letter = "K"; break;
        case Key.L: _Letter = "L"; break;
        case Key.Left: break;
        case Key.M: _Letter = "M"; break;
        case Key.Multiply: _Letter = "*"; break;
        case Key.N: _Letter = "N"; break;
        case Key.None: break;
        case Key.NumPad0: _Letter = "0"; break;
        case Key.NumPad1: _Letter = "1"; break;
        case Key.NumPad2: _Letter = "2"; break;
        case Key.NumPad3: _Letter = "3"; break;
        case Key.NumPad4: _Letter = "4"; break;
        case Key.NumPad5: _Letter = "5"; break;
        case Key.NumPad6: _Letter = "6"; break;
        case Key.NumPad7: _Letter = "7"; break;
        case Key.NumPad8: _Letter = "8"; break;
        case Key.NumPad9: _Letter = "9"; break;
        case Key.O: _Letter = "O"; break;
        case Key.P: _Letter = "P"; break;
        case Key.PageDown: break;
        case Key.PageUp: break;
        case Key.Q: _Letter = "Q"; break;
        case Key.R: _Letter = "R"; break;
        case Key.Right: break;
        case Key.S: _Letter = "S"; break;
        case Key.Shift: break;
        case Key.Space: _Letter = " "; break;
        case Key.Subtract: _Letter = "-"; break;
        case Key.T: _Letter = "T"; break;
        case Key.Tab: break;
        case Key.U: _Letter = "U"; break;
        case Key.Unknown: break;
        case Key.Up: break;
        case Key.V: _Letter = "V"; break;
        case Key.W: _Letter = "W"; break;
        case Key.X: _Letter = "X"; break;
        case Key.Y: _Letter = "Y"; break;
        case Key.Z: _Letter = "Z"; break;
        default: break;
    }
    var _Text = (sender as TextBox).Text + _Letter;
    double _Double;
    e.Handled = !double.TryParse(_Text, out _Double);
}

}

Biogeochemistry answered 23/11, 2011 at 4:21 Comment(1)
Key.D0 to Key.D9 do not represent numbers on AZERTY e.g. (only in combination with shift). That is just the start of fixing this code. So much for perfection...Endomorphic

© 2022 - 2024 — McMap. All rights reserved.