Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Validation between multiple fields in different levels

I have a problem with validations between multiple fields. For example, I have a ViewModel named RangeDateViewModel that contains 2 instances of a class named DateViewModel - they represent a start date and an end date respectively.

So my binding looks like this:

<TextBox Text="{Binding StartDate.Date, ValidateOnDataError=True}">
<TextBox Text="{Binding EndDate.Date, ValidateOnDataError=True}">

My RangeDateViewModel class implements the IDataErrorInfo interface. In my plan, the RangeDateViewModel would validate that the start date is before the end date, by applying the validation logic in the IDataErrorInfo["propertyName"] function like this:

public string this[string columnName]
{
     get
     {
        return ValidationError();
     }
}

The problem is that this is never being called, and instead the IDataErrorInfo properties that reside in each of the DateViewModel classes are being called instead.

I guess this is because the bound property is not in the same level of RangeDateViewModel, but instead inside the child DateViewModel.

I think my need is quite basic and there must be an easy solution for this problem.

I tried using ValidationRules instead of IDataErrorInfo but then I'd problems letting the ViewModel know of the current validation status from the ValidationRules.

like image 437
Dror Avatar asked Nov 05 '22 10:11

Dror


1 Answers

Try using the following approach:

  1. Create a DataTemplate for DateViewModel:

    <DataTemplate DataType="{x:Type ViewModels:DateViewModel}">
        <TextBox Text="{Binding Date}">
    </DataTemplate>
    
  2. Bind the instances of this ViewModel to a ContentControl and set ValidateOnDataError to true on that binding:

    <ContentControl Content="{Binding StartDate, ValidateOnDataError=True}" />
    <ContentControl Content="{Binding EndDate, ValidateOnDataError=True}" />
    
  3. In RangeDateViewModel subscribe to the PropertyChanged event of StartDate and EndDate and when raised, raise a PropertyChanged event with StartDate / EndDate:

    StartDate.PropertyChanged += (s, e) => InvokePropertyChanged("StartDate");
    EndDate.PropertyChanged += (s, e) => InvokePropertyChanged("EndDate");
    
like image 55
Daniel Hilgarth Avatar answered Nov 10 '22 13:11

Daniel Hilgarth