Validations properties within an object

Jan 31, 2013 at 3:17 PM
I have an VM that contains an externally generated 'Vehicle' object. I want to validate properties within that object from the container class.

AddRule(()=>vehicle.Registration, ()=>{....}); doesn't work.

Am I missing something?
Oct 24, 2013 at 1:29 PM
Hi,

is this because it does not support complex types or entites as such?
I guess there is only support on default types such as int, double, string etc.

Am i correct on this thought?

regards
greenlion
Coordinator
Oct 24, 2013 at 2:09 PM
The library knows nothing about particular types. It is important to understand that it doesn't do anything fancy here. When you do this: AddRule(()=>vehicle.Registration, ()=>{....}); it just means that now we have a validation rule that will be executed whenever you call Validate(() => vehicle.Registration) or ValidateAll(). And if the rule returns an invalid result, it means that a) ValidationResult object that you get as result of the Validate call will contain the error; b) the INotifyDataErrorInfo.ErrorsChanged event will be fired and its DataErrorsChangedEventArgs.PropertyName will be equal to "vehicle.Registration". That's it. After that, WPF (or Silverlight) binding system will handle the INotifyDataErrorInfo.ErrorsChanged event and display the error. The reason it does not work in this particular case is that probably there is no UI control that binds to "vehicle.Registration", hence WPF doesn't know where to show the error.

I would suggest to review the validation fundamentals in WPF (or Silverlight) and read about the INotifyDataErrorInfo interface. You can start, for example, here: http://www.jonathanantoine.com/2011/09/18/wpf-4-5-asynchronous-data-validation/.

The MVVM Validation Helpers library just helps you to implement the INotifyDataErrorInfo interface and makes it more convenient to configure validation rules.
Jul 21, 2015 at 12:03 PM
Am facing the same issue.
Here is what I have in ViewModel as validation rule, -
Validator.AddRule(() => AnotherObject, () => RuleResult.Assert(AnotherObject!= null, "Please select AnotherObject"));
Validator.AddRule(() => SelectedObject.MyField, () =>
{
 if(AnotherObject.SomeField=="WrongValue")
 {
  return RuleResult.Invalid("My Field is mandatory.");
 }
 return RuleResult.Valid();
});
Validator.AddChildValidatable(() => SelectedObject);
For validation I am doing like this, -
 private void Validate()
        {
            var uiThread = TaskScheduler.FromCurrentSynchronizationContext();
            Validator.ValidateAllAsync().ContinueWith(r => OnValidateAllCompleted(r.Result), uiThread);
        }
 private void OnValidateAllCompleted(ValidationResult validationResult)
        {
            if (validationResult.IsValid)
            {
                 //do stuff
            }
        }
On View I have the wiring like this, -
<ComboBox DisplayMemberPath="SomeField"
                      ItemsSource="{Binding AnotherObjects}"
                   SelectedItem="{Binding Path=AnotherObject, Mode=TwoWay, ValidatesOnDataErrors=True}"  />
<TextBox Text = "{Binding Path=SelectedObject.MyField,Mode=TwoWay, ValidatesOnDataErrors=True}" />
In this implementation, as you can see, there are two rules in the ViewModel. Both are working as far as validation is concerned but the on screen error message only comes in the first case. For second case I can see the error message in the step debug mode at validationResult; but that is not showing up on the screen. If I have any validation rule set within the class of SelectedObject for MyField then it is working as expected. but not in this fashion. What am I doing wrong?
Coordinator
Jul 21, 2015 at 12:56 PM
This is because the binding is looking for errors in "SelectedObject", but IDataErrorInfo returns the error for "SelectedObject.MyField". To workaround this, you can create a property in your view model like this:
public string SelectedObjectMyField
{
    get { return SelectedObject != null ? SelectedObject.MyField : null; }
    set
    {
        if (SelectedObject == null)
        {
            return;
        }

        if (SelectedObject.MyField != value)
        {
            SelectedObject.MyField = value;
            RaisePropertyChanged("SelectedObjectMyField");
        }
    }
}
Then register a validation rule for this property:
Validator.AddRule(() => SelectedObjectMyField, () =>
{
 if(SelectedObjectMyField=="WrongValue")
 {
  return RuleResult.Invalid("My Field is mandatory.");
 }
 return RuleResult.Valid();
});
PS:
You don't need this line:
Validator.AddChildValidatable(() => SelectedObject);
It is needed only if "SelectedObject" is also a view model with its own validation rules defined inside that view model.

Hope this helps.

Regards,
Pavlo
Jul 21, 2015 at 1:24 PM
:) actually I saw the workaround you mentioned already. But that seems a overkill. As instead of using the actual property to bind with the view, we are creating a dummy property so that the validation can work. Was looking for some solution with the existing object and property.
But then again, you don't get everything you wish for!
If this is the only solution we have then so be it. Thanks a million for your prompt reply!!
Coordinator
Jul 21, 2015 at 2:24 PM
You are welcome!