0

I've just started adding some validation to a WPF MVVM project. Validation in this paradigm is new to me, but it seems fairly straightforward:

public partial class Price : IDataErrorInfo
{
    public double Cost { get; set; }

    public string Error
    {
        get { throw new NotImplementedException(); }
    }

    string IDataErrorInfo.this[string columnName]
    {
        get
        {
            string message = null;
            if (columnName == "Cost" && this.Cost > 10000.00)
            {
                message = "This price is high enough to require confirmation";
            }
            return message;
        }
    }
}

The Cost property is bound in the ViewModel to a textbox, allowing the user to enter their own data. Prior to implementing IDataErrorInfo, users typing text in this box resulted in it being highlighted in red, but no error message was shown. That was deemed to be sufficient warning.

Now, typing text into the box flicks on the Style I've implemented to show errors and that's fine. Plus there's a message: Value '[text]' could not be converted, but that's a bit esotric for users. The real problem is that if someone types in a figure greater than 10000.00 and triggers the custom message and then removes that value and replaces it with text, the old error message stays in place.

With a breakpoint, it's clear what's happening: because the View is expecting this to be a double, it never even gets to checking to see if IDataErrorInfo has changed. How can I clear the error message and replace it with something more meaningful? I can't parse Cost because, of course, it's a double so it'll never even get set if someone enters text?

Cœur
  • 37,241
  • 25
  • 195
  • 267
Bob Tway
  • 9,301
  • 17
  • 80
  • 162
  • 1
    You could bind the textbox to a string property for this purpose and parse it to a double later. The other option would be to limit input to numeric values: http://stackoverflow.com/questions/1268552/how-do-i-get-a-textbox-to-only-accept-numeric-input-in-wpf – jHilscher Jan 13 '16 at 16:52
  • 1
    BTW: if Cost is a "money"-value you might want to consider using Decimal instead of Double: http://stackoverflow.com/questions/693372/what-is-the-best-data-type-to-use-for-money-in-c – jHilscher Jan 13 '16 at 16:55
  • @jHilscher Just tried that, thanks for the suggestion. The trouble is that as you parse it, the value "1234." fails parsing - so effectively it stops the user typing in decimals. With a bit of effort that approach might work, but I'd rather use IDataErrorInfo if possible. – Bob Tway Jan 13 '16 at 16:56
  • you can combine that with IDataErrorInfo and validate the string for that matter. – jHilscher Jan 13 '16 at 16:57

2 Answers2

1

The best would be to change type of the Cost property to string and try parse it in validation callback. There's no need to use any ValidationRules in XAML using this approach, just IDataErrorInfo.

More can be found in this article: https://joshsmithonwpf.wordpress.com/2008/11/14/using-a-viewmodel-to-provide-meaningful-validation-error-messages/ by Josh Smith.

Cheers

Tomas Petovsky
  • 285
  • 4
  • 14
1
 public class Price : IDataErrorInfo
{
    private double _costDouble;

    private string _cost;
    public string Cost
    {
        get {
            return _cost;
        } 
        set {
                _cost = value;
                double.TryParse(value, out _costDouble);
            } 
    }

    public string Error
    {
        get { throw new NotImplementedException(); }
    }

    string IDataErrorInfo.this[string columnName]
    {
        get
        {
            string message = null;
            if (columnName == "Cost")
            {
                double doubleVal;
                if (double.TryParse(this.Cost, out doubleVal))
                {
                    if (doubleVal > 1000.0)
                        message = "This price is high enough to require confirmation";
                }
                else {
                    message = "Format error";
                }
            }
            return message;
        }
    }
}

You ultimately have to use a String-Property for the Binding to the Textbox.

Bonus: You can now validate if the User enters a numeric value.

jHilscher
  • 1,810
  • 2
  • 25
  • 29