<p>How are you handling the entry of numeric values in WPF applications?</p>

<p>Without a NumericUpDown control, I've been using a TextBox and handling its PreviewKeyDown event with the code below, but it's pretty ugly.</p>

<p>Has anyone found a more graceful way to get numeric data from the user without relying on a third-party control?</p>

<pre><code>private void NumericEditPreviewKeyDown(object sender, KeyEventArgs e)
{
    bool isNumPadNumeric = (e.Key &gt;= Key.NumPad0 &amp;&amp; e.Key &lt;= Key.NumPad9) || e.Key == Key.Decimal;
    bool isNumeric = (e.Key &gt;= Key.D0 &amp;&amp; e.Key &lt;= Key.D9) || e.Key == Key.OemPeriod;

    if ((isNumeric || isNumPadNumeric) &amp;&amp; Keyboard.Modifiers != ModifierKeys.None)
    {
        e.Handled = true;
        return;
    }

    bool isControl = ((Keyboard.Modifiers != ModifierKeys.None &amp;&amp; Keyboard.Modifiers != ModifierKeys.Shift)
        || e.Key == Key.Back || e.Key == Key.Delete || e.Key == Key.Insert
        || e.Key == Key.Down || e.Key == Key.Left || e.Key == Key.Right || e.Key == Key.Up
        || e.Key == Key.Tab
        || e.Key == Key.PageDown || e.Key == Key.PageUp
        || e.Key == Key.Enter || e.Key == Key.Return || e.Key == Key.Escape
        || e.Key == Key.Home || e.Key == Key.End);

    e.Handled = !isControl &amp;&amp; !isNumeric &amp;&amp; !isNumPadNumeric;
}
</code></pre>

[{'answer_id': 6174, 'author': 'tags2k', 'author_id': 192, 'author_profile': 'https://Stackoverflow.com/users/192', 'pm_score': 1, 'selected': False, 'text': '<p>Call me crazy, but why not put plus and minus buttons at either side of the TextBox control and simply prevent the TextBox from receiving cursor focus, thereby creating your own cheap NumericUpDown control?</p>\n'}, {'answer_id': 7794, 'author': 'Arcturus', 'author_id': 900, 'author_profile': 'https://Stackoverflow.com/users/900', 'pm_score': 7, 'selected': True, 'text': '<p>How about:</p>\n\n<pre><code>protected override void OnPreviewTextInput(System.Windows.Input.TextCompositionEventArgs e)\n{\n    e.Handled = !AreAllValidNumericChars(e.Text);\n    base.OnPreviewTextInput(e);\n}\n\nprivate bool AreAllValidNumericChars(string str)\n{\n    foreach(char c in str)\n    {\n        if(!Char.IsNumber(c)) return false;\n    }\n\n    return true;\n}\n</code></pre>\n'}, {'answer_id': 8483, 'author': 'Nidonocu', 'author_id': 483, 'author_profile': 'https://Stackoverflow.com/users/483', 'pm_score': 2, 'selected': False, 'text': '<p>You can also try using data validation if users commit data before you use it. Doing that I found was fairly simple and cleaner than fiddling about with keys.</p>\n\n<p>Otherwise, you could always disable Paste too!</p>\n'}, {'answer_id': 28001, 'author': 'user3035', 'author_id': 3035, 'author_profile': 'https://Stackoverflow.com/users/3035', 'pm_score': 4, 'selected': False, 'text': '<p>I\'ve been using an attached property to allow the user to use the up and down keys to change the values in the text box. To use it, you just use</p>\n\n<pre><code>&lt;TextBox local:TextBoxNumbers.SingleDelta="1"&gt;100&lt;/TextBox&gt;\n</code></pre>\n\n<p>This doesn\'t actually address the validation issues that are referred to in this question, but it addresses what I do about not having a numeric up/down control. Using it for a little bit, I think I might actually like it better than the old numeric up/down control.</p>\n\n<p>The code isn\'t perfect, but it handles the cases I needed it to handle:</p>\n\n<ul>\n<li><code>Up</code> arrow, <code>Down</code> arrow</li>\n<li><code>Shift + Up</code> arrow, <code>Shift + Down</code> arrow</li>\n<li><code>Page Up</code>, <code>Page Down</code></li>\n<li>Binding <code>Converter</code> on the text property</li>\n</ul>\n\n<p><code>Code behind</code></p>\n\n<pre><code>using System;\nusing System.Collections.Generic;\nusing System.Text;\nusing System.Windows;\nusing System.Windows.Controls;\nusing System.Windows.Data;\nusing System.Windows.Input;\n\nnamespace Helpers\n{\n    public class TextBoxNumbers\n    {    \n        public static Decimal GetSingleDelta(DependencyObject obj)\n        {\n            return (Decimal)obj.GetValue(SingleDeltaProperty);\n        }\n\n        public static void SetSingleDelta(DependencyObject obj, Decimal value)\n        {\n            obj.SetValue(SingleDeltaProperty, value);\n        }\n\n        // Using a DependencyProperty as the backing store for SingleValue.  This enables animation, styling, binding, etc...\n        public static readonly DependencyProperty SingleDeltaProperty =\n            DependencyProperty.RegisterAttached("SingleDelta", typeof(Decimal), typeof(TextBoxNumbers), new UIPropertyMetadata(0.0m, new PropertyChangedCallback(f)));\n\n        public static void f(DependencyObject o, DependencyPropertyChangedEventArgs e)\n        {\n            TextBox t = o as TextBox;\n\n            if (t == null)\n                return;\n\n            t.PreviewKeyDown += new System.Windows.Input.KeyEventHandler(t_PreviewKeyDown);\n        }\n\n        private static Decimal GetSingleValue(DependencyObject obj)\n        {\n            return GetSingleDelta(obj);\n        }\n\n        private static Decimal GetDoubleValue(DependencyObject obj)\n        {\n            return GetSingleValue(obj) * 10;\n        }\n\n        private static Decimal GetTripleValue(DependencyObject obj)\n        {\n            return GetSingleValue(obj) * 100;\n        }\n\n        static void t_PreviewKeyDown(object sender, System.Windows.Input.KeyEventArgs e)\n        {\n            TextBox t = sender as TextBox;\n            Decimal i;\n\n            if (t == null)\n                return;\n\n            if (!Decimal.TryParse(t.Text, out i))\n                return;\n\n            switch (e.Key)\n            {\n                case System.Windows.Input.Key.Up:\n                    if (Keyboard.Modifiers == ModifierKeys.Shift)\n                        i += GetDoubleValue(t);\n                    else\n                        i += GetSingleValue(t);\n                    break;\n\n                case System.Windows.Input.Key.Down:\n                    if (Keyboard.Modifiers == ModifierKeys.Shift)\n                        i -= GetDoubleValue(t);\n                    else\n                        i -= GetSingleValue(t);\n                    break;\n\n                case System.Windows.Input.Key.PageUp:\n                    i += GetTripleValue(t);\n                    break;\n\n                case System.Windows.Input.Key.PageDown:\n                    i -= GetTripleValue(t);\n                    break;\n\n                default:\n                    return;\n            }\n\n            if (BindingOperations.IsDataBound(t, TextBox.TextProperty))\n            {\n                try\n                {\n                    Binding binding = BindingOperations.GetBinding(t, TextBox.TextProperty);\n                    t.Text = (string)binding.Converter.Convert(i, null, binding.ConverterParameter, binding.ConverterCulture);\n                }\n                catch\n                {\n                    t.Text = i.ToString();\n                }\n            }\n            else\n                t.Text = i.ToString();\n        }\n    }\n}\n</code></pre>\n'}, {'answer_id': 57784, 'author': 'Mark Allen', 'author_id': 5948, 'author_profile': 'https://Stackoverflow.com/users/5948', 'pm_score': 1, 'selected': False, 'text': '<p>Can you not just use something like the following?</p>\n\n<pre><code>int numericValue = 0;\n\nif (false == int.TryParse(yourInput, out numericValue))\n{\n    // handle non-numeric input\n}\n</code></pre>\n'}, {'answer_id': 561577, 'author': 'Community', 'author_id': -1, 'author_profile': 'https://Stackoverflow.com/users/-1', 'pm_score': 1, 'selected': False, 'text': '<pre><code>private void txtNumericValue_PreviewKeyDown(object sender, KeyEventArgs e)\n{\n    KeyConverter converter = new KeyConverter();\n\n    string key = converter.ConvertToString(e.Key);\n\n    if (key != null &amp;&amp; key.Length == 1)\n    {\n        e.Handled = Char.IsDigit(key[0]) == false;\n    }\n}\n</code></pre>\n\n<p>This is the easiest technique I\'ve found to accomplish this.  The down side is that the context menu of the TextBox still allows non-numerics via Paste.  To resolve this quickly I simply added the attribute/property:  ContextMenu="{x:Null}" to the TextBox thereby disabling it.  Not ideal but for my scenario it will suffice.</p>\n\n<p>Obviously you could add a few more keys/chars in the test to include additional acceptable values (e.g. \'.\', \'$\' etc...)</p>\n'}, {'answer_id': 1923737, 'author': 'Eric', 'author_id': 218177, 'author_profile': 'https://Stackoverflow.com/users/218177', 'pm_score': 4, 'selected': False, 'text': '<p>This is how I do it. It uses a regular expression to check if the text that will be in the box is numeric or not. </p>\n\n<pre><code>Regex NumEx = new Regex(@"^-?\\d*\\.?\\d*$");\n\nprivate void TextBox_PreviewTextInput(object sender, TextCompositionEventArgs e)\n{\n    if (sender is TextBox)\n    {\n        string text = (sender as TextBox).Text + e.Text;\n        e.Handled = !NumEx.IsMatch(text);\n    }\n    else\n        throw new NotImplementedException("TextBox_PreviewTextInput Can only Handle TextBoxes");\n}\n</code></pre>\n\n<p>There is now a much better way to do this in WPF and Silverlight. If your control is bound to a property, all you have to do is change your binding statement a bit. Use the following for your binding:</p>\n\n<pre><code>&lt;TextBox Text="{Binding Number, Mode=TwoWay, NotifyOnValidationError=True, ValidatesOnExceptions=True}"/&gt;\n</code></pre>\n\n<p>Note that you can use this on custom properties too, all you have to do is throw an exception if the value in the box is invalid and the control will get highlighted with a red border. If you click on the upper right of the red border then the exception message will pop up.</p>\n'}, {'answer_id': 2122964, 'author': 'Ritz', 'author_id': 257370, 'author_profile': 'https://Stackoverflow.com/users/257370', 'pm_score': 1, 'selected': False, 'text': '<pre><code>Private Sub Value1TextBox_PreviewTextInput(ByVal sender As Object, ByVal e As TextCompositionEventArgs) Handles Value1TextBox.PreviewTextInput\n    Try\n        If Not IsNumeric(e.Text) Then\n            e.Handled = True\n        End If\n    Catch ex As Exception\n    End Try\nEnd Sub\n</code></pre>\n\n<p>Worked for me.</p>\n'}, {'answer_id': 2165796, 'author': 'bcd', 'author_id': 262212, 'author_profile': 'https://Stackoverflow.com/users/262212', 'pm_score': 1, 'selected': False, 'text': '<pre><code>void PreviewTextInputHandler(object sender, TextCompositionEventArgs e)\n{\n    string sVal = e.Text;\n    int val = 0;\n\n    if (sVal != null &amp;&amp; sVal.Length &gt; 0)\n    {\n        if (int.TryParse(sVal, out val))\n        {\n            e.Handled = false;\n        }\n        else\n        {\n            e.Handled = true;\n        }\n    }\n}\n</code></pre>\n'}, {'answer_id': 2673131, 'author': 'juanagui', 'author_id': 168435, 'author_profile': 'https://Stackoverflow.com/users/168435', 'pm_score': 2, 'selected': False, 'text': '<pre><code>public class NumericTextBox : TextBox\n{\n    public NumericTextBox()\n        : base()\n    {\n        DataObject.AddPastingHandler(this, new DataObjectPastingEventHandler(CheckPasteFormat));\n    }\n\n    private Boolean CheckFormat(string text)\n    {\n        short val;\n        return Int16.TryParse(text, out val);\n    }\n\n    private void CheckPasteFormat(object sender, DataObjectPastingEventArgs e)\n    {\n        var isText = e.SourceDataObject.GetDataPresent(System.Windows.DataFormats.Text, true);\n\n        if (isText)\n        {\n            var text = e.SourceDataObject.GetData(DataFormats.Text) as string;\n            if (CheckFormat(text))\n            {\n                return;\n            }\n        }\n\n        e.CancelCommand();\n    }\n\n    protected override void OnPreviewTextInput(System.Windows.Input.TextCompositionEventArgs e)\n    {\n        if (!CheckFormat(e.Text))\n        {\n            e.Handled = true;\n        }\n        else\n        {\n            base.OnPreviewTextInput(e);\n        }\n    }\n}\n</code></pre>\n\n<p>Additionally you may customize the parsing behavior by providing appropriate dependency properties.</p>\n'}, {'answer_id': 2764514, 'author': 'BrownBot', 'author_id': 332246, 'author_profile': 'https://Stackoverflow.com/users/332246', 'pm_score': 2, 'selected': False, 'text': '<p>Add this to the main solution to make sure the the binding is updated to zero when the textbox is cleared.</p>\n\n<pre><code>protected override void OnPreviewKeyUp(System.Windows.Input.KeyEventArgs e)\n{\n    base.OnPreviewKeyUp(e);\n\n    if (BindingOperations.IsDataBound(this, TextBox.TextProperty))\n    {\n        if (this.Text.Length == 0)\n        {\n            this.SetValue(TextBox.TextProperty, "0");\n            this.SelectAll();\n        }\n    }\n}\n</code></pre>\n'}, {'answer_id': 2824205, 'author': 'erodewald', 'author_id': 24399, 'author_profile': 'https://Stackoverflow.com/users/24399', 'pm_score': 4, 'selected': False, 'text': '<p>I decided to simplify the reply marked as the answer on here to basically 2 lines using a LINQ expression.</p>\n\n<pre><code>e.Handled = !e.Text.All(Char.IsNumber);\nbase.OnPreviewTextInput(e);\n</code></pre>\n'}, {'answer_id': 4889675, 'author': 'Dead.Rabit', 'author_id': 424963, 'author_profile': 'https://Stackoverflow.com/users/424963', 'pm_score': 2, 'selected': False, 'text': '<p>My Version of <a href="https://stackoverflow.com/questions/5511/numeric-data-entry-in-wpf/7794#7794">Arcturus</a> answer, can change the convert method used to work with int / uint / decimal / byte (for colours) or any other numeric format you care to use, also works with copy / paste</p>\n\n<pre><code>protected override void OnPreviewTextInput( System.Windows.Input.TextCompositionEventArgs e )\n{\n    try\n    {\n        if ( String.IsNullOrEmpty( SelectedText ) )\n        {\n            Convert.ToDecimal( this.Text.Insert( this.CaretIndex, e.Text ) );\n        }\n        else\n        {\n            Convert.ToDecimal( this.Text.Remove( this.SelectionStart, this.SelectionLength ).Insert( this.SelectionStart, e.Text ) );\n        }\n    }\n    catch\n    {\n        // mark as handled if cannot convert string to decimal\n        e.Handled = true;\n    }\n\n    base.OnPreviewTextInput( e );\n}\n</code></pre>\n\n<p>N.B. Untested code.</p>\n'}, {'answer_id': 5546415, 'author': 'Jroonk', 'author_id': 692098, 'author_profile': 'https://Stackoverflow.com/users/692098', 'pm_score': 2, 'selected': False, 'text': "<p>Why don't you just try using the KeyDown event rather than the PreviewKeyDown Event.  You can stop the invalid characters there, but all the control characters are accepted.  This seems to work for me:</p>\n\n<pre><code>private void NumericKeyDown(object sender, System.Windows.Input.KeyEventArgs e)\n{\n    bool isNumPadNumeric = (e.Key &gt;= Key.NumPad0 &amp;&amp; e.Key &lt;= Key.NumPad9);\n    bool isNumeric =((e.Key &gt;= Key.D0 &amp;&amp; e.Key &lt;= Key.D9) &amp;&amp; (e.KeyboardDevice.Modifiers == ModifierKeys.None));\n    bool isDecimal = ((e.Key == Key.OemPeriod || e.Key == Key.Decimal) &amp;&amp; (((TextBox)sender).Text.IndexOf('.') &lt; 0));\n    e.Handled = !(isNumPadNumeric || isNumeric || isDecimal);\n}\n</code></pre>\n"}, {'answer_id': 8998307, 'author': 'Jonny Ots', 'author_id': 712714, 'author_profile': 'https://Stackoverflow.com/users/712714', 'pm_score': 2, 'selected': False, 'text': '<p>I use a custom <code>ValidationRule</code> to check if text is numeric.</p>\n\n<pre><code>public class DoubleValidation : ValidationRule\n{\n    public override ValidationResult Validate(object value, System.Globalization.CultureInfo cultureInfo)\n    {\n        if (value is string)\n        {\n            double number;\n            if (!Double.TryParse((value as string), out number))\n                return new ValidationResult(false, "Please enter a valid number");\n        }\n\n        return ValidationResult.ValidResult;\n    }\n</code></pre>\n\n<p>Then when I bind a <code>TextBox</code> to a numeric property, I add the new custom class to the <code>Binding.ValidationRules</code> collection.  In the example below the validation rule is checked everytime the <code>TextBox.Text</code> changes.</p>\n\n<pre><code>&lt;TextBox&gt;\n    &lt;TextBox.Text&gt;\n        &lt;Binding Path="MyNumericProperty" UpdateSourceTrigger="PropertyChanged"&gt;\n            &lt;Binding.ValidationRules&gt;\n                &lt;local:DoubleValidation/&gt;\n            &lt;/Binding.ValidationRules&gt;\n        &lt;/Binding&gt;\n    &lt;/TextBox.Text&gt;\n&lt;/TextBox&gt;\n</code></pre>\n'}, {'answer_id': 11858030, 'author': 'Varun', 'author_id': 1583635, 'author_profile': 'https://Stackoverflow.com/users/1583635', 'pm_score': 1, 'selected': False, 'text': '<p><strong>Can also use a converter like:</strong></p>\n\n<pre><code>public class IntegerFormatConverter : IValueConverter\n{\n    public object Convert(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)\n    {\n        int result;\n        int.TryParse(value.ToString(), out result);\n        return result;\n    }\n\n    public object ConvertBack(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)\n    {\n        int result;\n        int.TryParse(value.ToString(), out result);\n        return result;\n    }\n}\n</code></pre>\n'}, {'answer_id': 16807485, 'author': 'Brian Hinchey', 'author_id': 62278, 'author_profile': 'https://Stackoverflow.com/users/62278', 'pm_score': 2, 'selected': False, 'text': '<p>Combining the ideas from a few of these answers, I have created a NumericTextBox that</p>\n\n<ul>\n<li>Handles decimals</li>\n<li>Does some basic validation to ensure any entered \'-\' or \'.\' is valid</li>\n<li>Handles pasted values</li>\n</ul>\n\n<p>Please feel free to update if you can think of any other logic that should be included.</p>\n\n<pre><code>public class NumericTextBox : TextBox\n{\n    public NumericTextBox()\n    {\n        DataObject.AddPastingHandler(this, OnPaste);\n    }\n\n    private void OnPaste(object sender, DataObjectPastingEventArgs dataObjectPastingEventArgs)\n    {\n        var isText = dataObjectPastingEventArgs.SourceDataObject.GetDataPresent(System.Windows.DataFormats.Text, true);\n\n        if (isText)\n        {\n            var text = dataObjectPastingEventArgs.SourceDataObject.GetData(DataFormats.Text) as string;\n            if (IsTextValid(text))\n            {\n                return;\n            }\n        }\n\n        dataObjectPastingEventArgs.CancelCommand();\n    }\n\n    private bool IsTextValid(string enteredText)\n    {\n        if (!enteredText.All(c =&gt; Char.IsNumber(c) || c == \'.\' || c == \'-\'))\n        {\n            return false;\n        }\n\n        //We only validation against unselected text since the selected text will be replaced by the entered text\n        var unselectedText = this.Text.Remove(SelectionStart, SelectionLength);\n\n        if (enteredText == "." &amp;&amp; unselectedText.Contains("."))\n        {\n            return false;\n        }\n\n        if (enteredText == "-" &amp;&amp; unselectedText.Length &gt; 0)\n        {\n            return false;\n        }\n\n        return true;\n    }\n\n    protected override void OnPreviewTextInput(System.Windows.Input.TextCompositionEventArgs e)\n    {\n        e.Handled = !IsTextValid(e.Text);\n        base.OnPreviewTextInput(e);\n    }\n}\n</code></pre>\n'}]
['https://Stackoverflow.com/questions/5511', 'https://Stackoverflow.com', 'https://Stackoverflow.com/users/615/']