0

I want validate textbox IN WPF MVVM pattern server side to allow number with decimal value, like

1O.10
10.01
2.22
3.444
1234.676

but not alphanumerics like

FHFJ
XTHKX
SPECIAL CHARATER(@#$$)
67..8787

This my code snippet

enter image description here

enter image description here

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
  • `TryParse` method would be a good start. – Ryan Wilson Feb 15 '23 at 13:29
  • does this help you? https://stackoverflow.com/questions/16914224/wpf-textbox-to-enter-decimal-values – amitklein Feb 15 '23 at 13:29
  • Why aren't you just binding to a decimal property? It won't even get set if the data is not a valid double. – Andy Feb 15 '23 at 17:43
  • BTW it is a complication validating double input character by character. Textbox twoway binding means a character at a time transfers textbox to viewmodel and then back again to the textbox. Someone decides it's a great plan to format that decimal and weird things happen like the user can't input a decimal point. – Andy Feb 16 '23 at 09:16

4 Answers4

0

A View Model based solution may look as following:

    double _MyValidNumber;
    string _MyNumber;
    public string MyNumber
    {
        get
        { 
            return _MyNumber;
        }
        set
        {
            _MyNumber = value;
            double _temp;
            string toBexamined = value;
            if (!toBexamined.Contains("."))
            {
                toBexamined += ".0";
            }
            if (toBexamined.EndsWith("."))
            {
                toBexamined += "0";
            }
            if (!double.TryParse(toBexamined, out _temp))
            {
                _MyNumber = _MyValidNumber.ToString();
            } 
            else
            {
                _MyValidNumber = _temp;
            }
            NotifyPropertyChanged(nameof(MyNumber)); }
    }
    
Gilad Waisel
  • 120
  • 4
0

I would like to present a solution that is based on using a User Control - TextBoxDouble.

How we use it :

 <local:TextBoxDouble Number="{Binding SimpleNumber,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"/>

the TextBoxDouble XAML is as following:

<UserControl x:Class="Problem19_ValidateANumber.TextBoxDouble"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:Problem19_ValidateANumber"
             mc:Ignorable="d" 
             d:DesignHeight="450" d:DesignWidth="800" Name="Parent">
    <Grid>
        <TextBox Text="{Binding ElementName=Parent,Path=Text,UpdateSourceTrigger=PropertyChanged,Mode=TwoWay}"   />
    </Grid>
</UserControl>

In the Code Behind we have defined 2 dependency properties: Text and Number. The 2 properties exchange the data. The Text Property is for the UI side and the Number is for the View Model property side.

public partial class TextBoxDouble : UserControl
    {
        public TextBoxDouble()
        {
            InitializeComponent();
        }
        public string Text
        {
            get { return (string)GetValue(TextProperty); }
            set {

                SetValue(TextProperty, value);
                SetValue(TextProperty, value); 
            }
        }
        public static readonly DependencyProperty TextProperty =
            DependencyProperty.Register("Text", typeof(string), typeof(TextBoxDouble),
              new PropertyMetadata(string.Empty, new PropertyChangedCallback(TextPropertyChanged)));

       

        public double Number
        {
            get { return (double)GetValue(NumberProperty); }
            set
            {
                SetValue(NumberProperty, value);
            }
        }
        public static readonly DependencyProperty NumberProperty =
           DependencyProperty.Register("Number", typeof(double), typeof(TextBoxDouble),
             new PropertyMetadata(double.NaN, new PropertyChangedCallback(NumberPropertyChanged)));

        private static void TextPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
        {

            TextBoxDouble ours = (TextBoxDouble)obj;
            if (e.NewValue == e.OldValue) return;

            double _temp;
            string toBexamined = (string)e.NewValue;
            if (!toBexamined.Contains("."))
            {
                toBexamined += ".0";
            }
            if (toBexamined.EndsWith("."))
            {
                toBexamined += "0";
            }
            if (!double.TryParse(toBexamined, out _temp))
            {
                ours.SetValue(TextProperty, ours.Number.ToString());
            }
            else
            {
                ours.SetValue(NumberProperty, _temp);
            }
        }
        private static void NumberPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
        {
            TextBoxDouble ours = (TextBoxDouble)obj;
            if (e.NewValue == e.OldValue) return;
            ours.SetValue(TextProperty, ours.Number.ToString());
        }
    }
Gilad Waisel
  • 120
  • 4
0

Similar to what @Gilad Waisel suggested. I think the most simplest ways would be just to extend the TextBox class and enter your desired validation into the TexhChangeEvent:

  public class TextBoxDecimal : TextBox
    {
        readonly string CurrentSeperator;
        public TextBoxDecimal()
        {
            CultureInfo cultureInfo = CultureInfo.CurrentCulture;
            CurrentSeperator = cultureInfo.NumberFormat.CurrencyDecimalSeparator;
        }
        protected override void OnTextInput(TextCompositionEventArgs e)
        {
            if (double.TryParse(e.Text, out var value))
                base.OnTextInput(e);
            else if (e.Text == CurrentSeperator && !Text.Any(x => x == CurrentSeperator[0]))
                base.OnTextInput(e);
        }
    }

This is not conflicting with MVVM however does operate ONLY on the UI side.

Demon
  • 379
  • 2
  • 7
0

Below is the working code to accept only double value:

    decimal _MyValidNumber;
    string _MyNumber;
    public string MyNumber
    {
        get
        {
            return _MyNumber;
        }
        set
        {
            if (decimal.TryParse(value, out decimal result))
            {
                _MyValidNumber = result;
                _MyNumber = value;
            }
            else
            {
                _MyNumber = "";
            }

            NotifyPropertyChanged(nameof(_MyNumber));
        }
    }
alpha
  • 71
  • 3