none
INotifyDataErrorInfo and MVVM

    Question

  • I am having trouble getting the validations to work when using the MVVM patern.

    It works fine for simple binding but not for binding to properties of a property class.

    for example I have a cMeter class that has a Reading property.

    The cMeter class is a property on my View Model

    cMeter implements INotifyPropertyChanged and the handler for that event in the view model sets the errors.

    But I can not get the validation to recognize that an validation has failed in the property class.

    Any help would be greatly appreciated.

    Here is the relevent part of my View Model:

     public MainPageViewModel()
            {
                _currentErrors = new Dictionary<string, List<string>>();
                Meter = new cMeter();
                Meter.PropertyChanged += new PropertyChangedEventHandler(Meter_PropertyChanged);
            }
    
            void Meter_PropertyChanged(object sender, PropertyChangedEventArgs e)
            {
                if (Meter.Reading < 10)
                {
                    AddErrorForProperty("Meter.Reading", "too small 1");
                    AddErrorForProperty("Meter", "too small 2");
                    AddErrorForProperty("Reading", "too small 3");
                }
            }
            public void AddErrorForProperty(string property, string error)
            {
                if (!_currentErrors.ContainsKey(property))
                {
                    _currentErrors[property] = new List<string>();
                } 
                _currentErrors[property].Add(error);
                FireErrorsChanged(property);
            }
            void FireErrorsChanged(string property)
            {
                if (ErrorsChanged != null)
                {
                    ErrorsChanged(this, new DataErrorsChangedEventArgs(property));
                }
            }
    
    
    Thanks
    Richard
    Wednesday, October 19, 2011 9:59 AM

All replies

  • Hi Richard,

    According to the code you provided, I think it is ok.

    It would be appreciated if you can share me the code of cMeter and xaml in order to have a test.

    And for more silverlight validation:

    http://msdn.microsoft.com/en-us/magazine/ee335695.aspx

    http://www.codeproject.com/KB/silverlight/Silverlight4_Validation.aspx

    Hope it can help

    Friday, October 21, 2011 9:24 PM
  • AddErrorForProperty("Meter.Reading", "too small 1");

    I'm not aware of what would make this scenario work.  I've been looking into it myself.  As an alternative I would consider adding a direct property on your ViewModel that serves as a pass-through to the property on your Model (Meter class).  You then bind the control to that pass-through property that is directly on the ViewModel.  You don't have to replicate every property from the Model onto the ViewModel.  I can tell you wanted to avoid that considering that Model might have over 100 properties!  What a bloated ViewModel that would become!  Instead, you just replicate a property for every control in the view that needs validation.

    Monday, February 06, 2012 11:20 AM
  • I'm having this same problem right now.  I tried adding a main viewmodel property and having the getters and setters change the original property (Categories.Category1Choices).  But of course, the old code doesn't know anything about the new property.  That code continues to update the Category1Choices and not the new property that is bound to the control.

    And in this case, the control is a ComboBox and the property in error is what is bound to the ItemsSource.

    Not easy to accomplish.  It would be hard to find and change all the places that could potentially change the Category1Choices.  It took weeks to get the logic right on that as it is.

    Is there NO other solution? 

    Can't we somehow fire it?  Or maybe CHANGE its visual state using VSM?

    Monday, February 06, 2012 2:32 PM
  • I can't even figure out how to do that.  My Viewmodel doesn't know anything about my View so it doesn't know what control to change the state of.  Maybe have to try to find bindingexpression or something...

    Nothing is ever easy.

    Monday, February 06, 2012 2:42 PM
  • Nope, I need a control to get the bindingexpression....

    Anybody got a good way of notifying a control to change its state from a viewmodel that doesn't know the control exists?

    Monday, February 06, 2012 2:44 PM
  • I also tried raising an exception in the SelectedItem bound property setter method.  No Invalid state displayed.

    How can I make this thing work?

    Tuesday, February 07, 2012 10:12 AM
  • Oops.  Missed one of the THREE options that should be specified.  Now I have a test case that works fine and my real app doesn't.  I am using INotifyDataErrorInfo.  I can see the notification happening, but it never tries to GetErrors.

    But the simple case does seem to work and set the visual state.  Even with the Categories.SelectedCategory type syntax in the binding.  But this doesn't work:

       <ComboBox 
          x:Name="Category1Combo"
          ItemsSource="{Binding  Categories.Category1Choices}" 
          SelectedItem="{Binding Categories.SelectedCategory1, Mode=TwoWay, 
    NotifyOnValidationError=True, ValidatesOnDataErrors=True, ValidatesOnExceptions=True }" DisplayMemberPath="Name" />

    I'm doing a bunch of special stuff because the ValidationSummary doesn't work as it should, but the summary seems fine.  Just the notifcation seems off.

    Tuesday, February 07, 2012 4:49 PM
  • Richard,

       You don't show that your viewmodel implements INotifyDataErrorInfo.  Did you leave that out of the example?  Without implementing that interface, I don't think it will call the GetErrors in order to display them.  So you have to raise the ErrorsChanged AND supply the errors when they are called for.

    Tuesday, February 07, 2012 5:01 PM
  • See http://social.msdn.microsoft.com/Forums/en-US/silverlightmvvm/thread/7b092f66-0b2d-4b52-952d-bfeb156dd4b5//1?INotifyDataErrorInfo+MVVM+issue

    Tuesday, February 28, 2012 10:35 PM
  • I ended up SPECIFYING the DataContext so that the binding was on a simple property.  I don't like having to do this because if I forget, notification will break.

    <ComboBox 
       x:Name="Category1Combo"
       DataContext= "{Binding Categories}"
       ItemsSource= "{Binding Category1Choices}" 
       SelectedItem="{Binding SelectedCategory1, Mode=TwoWay, 
    NotifyOnValidationError=True, ValidatesOnDataErrors=True, ValidatesOnExceptions=True }" DisplayMemberPath="Name" />
    Wednesday, February 29, 2012 8:28 AM