How do I run IDataErrorInfo validation code when my IValueConverter throws an exception?

I am having problems validating integers in a WPF window. My business object has a property Age:int

. I want to confirm this Age >= 5

. I can see how to do this with IDataErrorInfo

and set ValidatesOnDataErrors

to true. This works if I enter a number. But if I enter an empty string or "abc"

, the verification code will not be called. This is a problem because I have a button that I only want to enable if the validation code completes successfully.

According to my output window, the problem is that the default transformer is throwing FormatException

into the method ConvertBack

. This prevents the method from calling the code IDataErrorInfo.this[string columnName]

. (I am currently using the default converter int

)

I've read about several solutions for this, but they either don't work or seem to be a hack:

  • Use Nullable <int>. This does not exclude an exception.
  • Use string instead of int. This will work, but it prevents me from using the built-in WPF functionality. It looks like a hack.
  • I thought I could use my own IValueConverter

    to intercept the ConvertBack call, but I need to give the converter access to my business object so that it can set some property IsValid:bool

    . I don't know how to provide the converter with a link to my business object.

How can I check my business object when it ConvertBack

throws an exception (for example, the user enters an empty string)?


Here's my business object:

class DContext : INotifyPropertyChanged, IDataErrorInfo
{
    public DContext()
    {
        this._submit = new Commands.btnSubmit(this);
    }

    private readonly ICommand _submit;
    public ICommand Submit { get { return this._submit; } }

    private int _age;
    public int Age
    {
        get { return this._age; }
        set
        {
            if (this._age != value)
            {
                this._age = value;
                this.OnPropertyChanged();
            }
        }
    }

    private string _error;
    public string Error
    {
        get { return this._error; }
    }

    public string this[string columnName]
    {
        get 
        {
            this._error = null;
            if (columnName == "Age" && this._age < 5)
                this._error = "Age must be >= 5";

            return this._error;
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    private void OnPropertyChanged([System.Runtime.CompilerServices.CallerMemberNameAttribute]string propertyName = "")
    {
        if (this.PropertyChanged != null)
            this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
}

      

Here's my WPF:

<StackPanel Orientation="Horizontal" Height="20" VerticalAlignment="Top">
    <TextBlock Text="Age" />
    <TextBox Width="100" Text="{Binding Age,ValidatesOnDataErrors=True}" />
    <Button Content="Submit" Command="{Binding Submit}" />
</StackPanel>

      


Interestingly, I noticed that the method ICommand.CanExecute

is called before the method IDataErrorInfo.this[string columnName]

. This means it ICommand

works with values ​​that have not yet been verified. This means I will have to duplicate my error detection code.

+3


source to share


1 answer


I think the solution should be either # 2 or # 3. I would lean towards # 3 because it doesn't introduce any clutter into your view model. Try the "ConvertBack" method to parse the input and return an invalid value (possibly 0 or -1) if the parsing fails.

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        string input = value as string;
        int validNumber;
        if (input != null && int.TryParse(input, out validNumber))
            return validNumber;
        else
            return 0;
    }

      

Your check should work with this without any changes. The only reason I could use # 2 instead is if you want different error messages like "Age field is required" and "Age field must be a valid number".



This means that ICommand works with values ​​that have not yet been verified. This means I will have to duplicate my error detection code.

I'm not sure why this is needed. Can't you just bring up "Command.CanExecuteChanged" whenever your check is done? If not, then you might want to use INotifyDataErrorInfo

instead IDataErrorInfo

, as this allows you to raise the "ErrorsChanged" event to trigger the check.

+1


source







All Articles