WPF TextBox to enter decimal values

2019-01-06 22:36发布

Is there any decent way to get a WPF control which is bound to a decimal value?

When I just bind the TextBox or DataGridTextColumn to a decimal, data entry sucks big time.

<TextBox Text="{Binding MyDecimal, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}"/>

When I try to enter "0,5" in this TextBox I'll get "5" as a result. It is nearly impossible to enter "0,5" at all (Apart from entering 1,5 and replacing the "1" with a "0").

When I use StringFormat data entry still sucks small time:

<TextBox Text="{Binding MyDecimal, StringFormat=F1, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}"/>

Now when I try and enter "0,5" I'll end up with "0,5,0", which still is wrong but at least I can remove the trailing ",0" without much Problems.

Still, entering decimals using WPF sucks big time because this entry fields are very prone to data entry errors, which is a real pain especially for values!

So what am I supposed to use for decimal data entry in wpf? Or does Microsoft not support decimal data??

9条回答
萌系小妹纸
2楼-- · 2019-01-06 22:40

Im new, so I cant comment his answer, but I fixed the negative number issues in blindmeis's code.

Just modify the

if (input.Contains("-"))

section of IsValidInput() to...

                if (input.Contains("-"))
                {
                    if (this.JustPositivDecimalInput)
                        return false;

                    //minus einmal am anfang zulässig
                    //minus once at the beginning
                    if (input.IndexOf("-", StringComparison.Ordinal) == 0 && input.ToCharArray().Count(x => x == '-') == 1)
                    {
                        if(input.Length == 1)
                        {
                            //INPUT IS "-"
                            return true;
                        }
                        else if (input.Length == 2)
                        {
                            //VALIDATE NEGATIVE DECIMALS...INPUT IS "-."
                            if (input.IndexOf(".", StringComparison.Ordinal) == 1)
                            {
                                return true;
                            }
                        }
                        else 
                        {
                            return decimal.TryParse(input, validNumberStyles, CultureInfo.CurrentCulture, out d);
                        }
                    }
                }
查看更多
何必那么认真
3楼-- · 2019-01-06 22:41

I also came across this issue; with UpdateSourceTrigger=PropertyChanged it seems that the binding tries to update the text as you are typing it. To fix this issue we changed our input fields so that UpdateSourceTrigger=LostFocus, e.g.:

<TextBox Text="{Binding MyDecimal, UpdateSourceTrigger=LostFocus, ValidatesOnDataErrors=True, StringFormat=n1}" />

You can define your own validation errors by using the IDataErrorInfo interface. You just need to add the following to your backing model:

 public class MyModel : IDataErrorInfo
 {
    /* my properties */

    public string Error { get { return null; } }
    public string this[string name]
    {
       get
       {
          switch (name)
          {
             case "MyDecimal":
                return NumberHelper.IsValidValue(MyDecimal) ? message : null;
             default: return null;
          }
       }
    }
    private string message = "Invalid value";
 }
查看更多
甜甜的少女心
4楼-- · 2019-01-06 22:44

I implemented my own TextBox. It updates the source, when there is a number in the text, otherwise not. On lost Focus, I read the source property. All you have to do is replace the TextBox with this class and bind the "Number" Property which is of type double.

public class DoubleTextBox: TextBox
{
    public DoubleTextBox()
    {
        TextChanged += DoubleTextBox_TextChanged;
        LostFocus += DoubleTextBox_LostFocus;
    }

    void DoubleTextBox_LostFocus(object sender, System.Windows.RoutedEventArgs e)
    {
        Text = Number.ToString("N2");
    }

    void DoubleTextBox_TextChanged(object sender, TextChangedEventArgs e)
    {
        double zahl;
        if (string.IsNullOrWhiteSpace(Text))
        {
            Number = 0;
        }
        else if (double.TryParse(Text, out zahl))
        {
            Number = Double.Parse(zahl.ToString("N2"));
        }
        else
        {
            ValidationError validationError =
                new ValidationError(new ExceptionValidationRule(), GetBindingExpression(NumberProperty));

            validationError.ErrorContent = "Keine gültige Zahl";

            Validation.MarkInvalid(
                GetBindingExpression(NumberProperty),
                validationError);

        }
    }

    public double Number
    {
        get { return (double)this.GetValue(NumberProperty); }
        set { this.SetValue(NumberProperty, value); }
    }

    public static readonly DependencyProperty NumberProperty = DependencyProperty.Register(
        "Number", typeof(double), typeof(DoubleTextBox), 
        new FrameworkPropertyMetadata
            (
                0d,
                FrameworkPropertyMetadataOptions.BindsTwoWayByDefault
            )
    );
}
查看更多
疯言疯语
5楼-- · 2019-01-06 22:52

This regex works

private void TextBox_PreviewTextInput(object sender, TextCompositionEventArgs e)
  {
   Regex regex = new Regex("^[.][0-9]+$|^[0-9]*[.]{0,1}[0-9]*$");
   e.Handled = !regex.IsMatch((sender as TextBox).Text.Insert((sender as TextBox).SelectionStart,e.Text));
  }
查看更多
走好不送
6楼-- · 2019-01-06 22:54

if you want the textbox to only allow decimal then write previewinputtext event for that textbox. then in that event write this code

decimal result;
e.Handled=!decimal.TryParse((sender as TextBox).Text + e.Text, out result)
查看更多
狗以群分
7楼-- · 2019-01-06 23:00

The WPF Extended toolkit has a DecimalUpDown control that may suit your needs. It's free to use, and it's better to use this than to try and roll your own.

As for validating the input on it, there are a number of ways of applying validation, here is one detailed in MSDN. I detail another approach for custom bindable validation in two posts on my blog (you would apply the validation to the Value property binding on the DecimalUpDown control).

查看更多
登录 后发表回答