Validation with Simple MVVM Toolkit

In version 2.1 of Simple MVVM Toolkit I added support for validation with INotifyDataErrorInfo. This interface obsolesces IDataErrorInfo because it does everything that interface did but enables additional functionality:

  • Multiple validation errors per property
  • Entity-level validation
  • Asynchronous server-side validation

INotifyDataErrorInfo is supported by Silverlight 4, but it is not supported by WPF and will only have limited support in Windows Phone 7.1. The interface is defined as follows:

public interface INotifyDataErrorInfo
{
    bool HasErrors { get; }
    event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;
    IEnumerable GetErrors(string propertyName);
}

I believe the best place to implement this interface is at the model-level.  In WCF RIA Services, for example, the Entity class, which is the base class for client-side entities, implements INotifyDataErrorInfo.  Similarly, the ModelBase class in the SimpleMvvmToolkit namespace, implements this interface, for scenarios in which you are not using WCF RIA Services.

In the ViewModelDetailBase class, which accepts a TModel type argument, supports validation with an IsValid property.  It checks to see if the model implements INotifyDataErrorInfo and, if so, returns true if the HasErrors property is true.  When a PropertyChanged event fires on the model, ViewModelDetailBase calls NotifyPropertyChanged for the IsValid property.  You might, for example, bind the IsEnabled property of a Save button to the IsValid property of the ViewModel.  When properties are changed on the Model, the Save button would be disabled if there were any validation errors.

Performing validation with INotifyDataErrorInfo is very powerful.  It integrates well with DataAnnotations, so that you can apply attributes to class properties to enforce validation.  By default, the Binding markup extension supports INotifyDataErrorInfo and will transition to a validation visual state when the ErrorsChanged event fires.  Here is an example of requiring a non-blank value with a maximum string length of 50 characters for the Name property of the Item entity

class Item
{
    [Required()]
    [StringLength(50)]
    public string Name
    {
        get
        {
            return this._name;
        }
        set
        {
            if ((this._name != value))
            {
                this.ValidateProperty("Name", value);
                this._name = value;
                this.RaiseDataMemberChanged("Name");
            }
        }
    }
}

While you could write this code yourself, deriving the Item entity from ModelBase, there’s no need if you are using WCF RIA Services, which automatically inserts the [Required] and [StringLength] attributes based on the database column attributes. The ValidateProperty method calls Validator.TryValidateProperty under the covers, which uses reflection to inspect the data annotation attributes and populate the errors collection for that property. (For more information on entity-level and async validation, see my webinar on WCF RIA Services.)  When there are one or more validation errors, you’ll see a red outline around the offending textbox with a label showing the error message.

item_validation

Notice that the OK button is disabled while there are validation errors.  That is accomplished simply by binding IsEnabled on the button to IsValid on the ViewModel.

<Button Content="OK" Click="OKButton_Click"  
    IsEnabled="{Binding Path=IsValid, Mode=TwoWay}"/>

This example uses a handler in the View code-behind, but more likely you would use either an event trigger (with the Blend SDK installed) or a command with a CanExecute method. (I’ll elaborate on triggers versus commands, and when to use each, in a future post.)

While we’re on the topic of validation, it seems appropriate to discuss another feature added to version 2.1 of the toolkit, which is dirty-checking.  ViewModelDetailBase now sports an IsDirty property.  IsDirty calls an extension method called AreSame, which compares an entity with the clone that is created when BeginEdit is called.  This method simply or’s together the hash codes of each property on the objects and compares them.  Complex objects can override GetHashCode to implement custom comparisons.

One thing I’d like to mention that that, when it comes to validation and dirty-checking, there are certain properties you might want to exclude.  For example, entities in RIA Services have all kinds of properties that you would want to exclude from dirty-checking (EntityState, EntityConflict, EntityActions, etc). ViewModelDetailBase therefore has ModelMetadataProperties property with a list of property names excluded from both validation and dirty-checking.  It is defined as virtual so you can replace it if you wish.

To see validation in action, simply download and install the Simple MVVM Toolkit, then open up the SimpleMvvm-RiaValidation sample application and look at the ItemListViewModel class.

About Tony Sneed

Sr. Software Solutions Architect, Hilti Global Application Software
This entry was posted in Technical and tagged . Bookmark the permalink.

20 Responses to Validation with Simple MVVM Toolkit

  1. dshakya says:

    Hi Tony,
    Thanks for the update with validation included. The documentation shows that you can use the property validation as:

    this.ValidateProperty(“Name”, value);

    But this does not work as the base model using lambda expression. I was wondering why my existing code was giving errors which was implemented as in your documentation.

    Now I have the validation as:
    ValidateProperty(p => p.DevelopmentArea,value);

    and it seems to work.

    Thanks again!

    • Tony Sneed says:

      Good observation! If you are using WCF RIA Services, the code-generated client entities call ValidateProperty for you, passing a string for the property name. So you don’t have to do anything to trigger validation other than allowing the user to set the property by entering a value and tabbing onto the next control (unless you set the UpdateSourceTrigger on the binding to Explicit and fire the binding in code).

      As you can probably tell, I’m a huge fan of WCF RIA Services. By re-invest the wheel when things like validation, change-tracking and authentication are offered for free right out of the box? That said, I recognize there are scenarios where it is not possible to use WCF RIA Services. Perhaps you have no control over the service and data layers at all. Or maybe you’re not writing an n-tier application at all.

      It is for these scenarios that I implemented INotifyDataErrorInfo in the ModelBase class. The way I expose the ValidateProperty method is by accepting a lambda expression rather than a string for the property name — which is type-safe and can help you catch errors at compile time when you change a property name.

      Again, if you are using WCF RIA Services, there is no reason for you to use ModelBase class at all. But it’s there in case you need it.

  2. dshakya says:

    Hi Tony,

    I think snippet for validation would be great as well. 😉

    Cheers!

    • Tony Sneed says:

      You know, I decided against a separate code-snippet, mainly to avoid confusion. I advocate implementing INotifyDataErrorInfo at the Model level rather than at the ViewModel level. The reason is that Simple MVVM Toolkit has a ViewModelDetailBase class that accepts a TModel type argument and exposes a Model property. (See this discussion thread: http://simplemvvmtoolkit.codeplex.com/discussions/264778.) Most of the time a client app is consuming a WCF service, which generates or uses Model entities that implement INotifyDataErrorInfo. It’s a less common scenario to use ModelBase, and it’s only when deriving model classes from ModelBase that you would want to call ValidateProperty. Whereas, you could very well expose properties from a ViewModel that require two-way data binding but do not involve validation (for example, IsBusy, IsDirty, IsValid, HasOrders, etc).

  3. Pingback: Validation with Simple MVVM Toolkit | WCF, Database, WPF, Windows and Silverlight | Syngu

  4. dshakya says:

    Thanks Tony for the explanation. I am building the app using your toolkit and it is helping a lot. I hope its popularity picks up real quick in Silverlight development.

    Thanks again.

  5. Phil says:

    Hi Tony,
    I am very new to the Silverlight and WCF RIA Services and even to message boards so apologies if this question is misplaced. However I have been using SimpleMVVM (which I find extremely useful so thank you!) for a basic POC I am putting together and as per your screencast examples have created my own user list viewmodel and user detail viewmodels. I am also using WCF RIA Services to create my User class on the client. User contains a complex object called UserAddress, which as you can imagine stores basic address properties (Street, City, State etc).

    Within the UserListViewModel when I want to edit a User I create a UserDetailViewModel passing in the user to be editted, and my serviceagent (not per your screencast example but I need more information to be loaded to populate a combobox).
    UserDetailViewModel detailModel =
    new UserDetailViewModel(SelectedUser, serviceAgent);

    // Start editing
    detailModel.BeginEdit();

    // Show ProductDetail view
    UserDetailView itemDetail = new UserDetailView(detailModel);
    itemDetail.Closed += (s, ea) =>
    {
    if (itemDetail.DialogResult == true)
    {
    // Confirm changes
    detailModel.EndEdit();
    }
    else
    {
    // Reject changes
    detailModel.CancelEdit();
    }
    };

    The problem arises when I hit the OK button in my UserDetailView child window and the EndEdit() method is called. The error I receive is
    “ComplexObject instances cannot be shared.”
    and this appears within the WCF RIA Services generated client code for User Address on the line
    this.ValidateProperty(“UserAddress”, value);

    Do you have any idea what is causing this? Again I apologise if this has nothing to do with the SimpleMVVM toolkit but I am struggling to find any information on this error.

    Thanks in advance,
    Phil

  6. Hi Tony, i’m using de SimpleMVVM Toolkit, and i created a WPF Aplication , not Silverlight. The question is, how can I Implement the Validations in WPF.

    • Tony Sneed says:

      Just derive your entities from ModelBase – I have support for validation there.

      Tony

      • Scott says:

        Tony,

        Do you have a quick sample you can post for a WPF application to handle Validation with the Simple MVVM Toolkit?

        Thanks.

        Scott

      • Tony Sneed says:

        Don’t have one specifically for WPF, but the sample for Silverlight applies to WPF as well, and that can be extracted from the zip file in the samples folder after installation.

  7. Excelent ToolKit with great explnation samples. really great.

  8. Scott says:

    Tony,

    I put together a sample WPF application that uses IDataErrorInfo and I thought it might be helpful for you to check it out and post it for others to see.

    Is there a place that I could send you the Zip file (whether it be on e-mail or upload it to a blog)?

    Thanks.

    Scott

  9. Tony says:

    Hi Scott & Tony.

    wouldn’t mind a peek at that myself…
    Do you have it uploaded anywhere?

    Cheers,
    Tony.

  10. Tony Sneed says:

    I checked my Inbox and couldn’t find Scott’s email. Scott, if you are monitoring this post, could you re-send it to me? Or you could use DropBox to share it with me.

    Cheers, Tony

  11. Tony says:

    Cheers, Tony.

    I have version 3 and am using the wpf version and couldn’t see the any of the validation that’s in the silverlight version so I’m going to go down the IDataErrorInfo route too so I’ll keep an eye open.

    Cheers,
    Tony.

  12. JP says:

    For those who are trying to get validation to work in WPF, here’s are some key pieces of the puzzle to make it work.
    1. Your Model should inherit from ModelBase.
    2. Your ViewModel should inherit from ViewModelDetailBase.
    3. In your view, bind your TextBox Text property to Model.Name (or whatever properties are on your model). The Model property is inherited from ViewModelDetailBase.
    4. In the ViewModel, the inherited Model property should be set to the model item being edited/added.
    5. In the ViewModel, after you set the Model property, call the inherited BeginEdit() method.
    6. Your model inherits the method ValidateProperty() from ModelBase. Use this method to validate your model with values specified. This is the method that should be called every time a user changes the value in this textbox. That’s also a part you yourself are responsible for.
    7. After all this, validation should appear to start working. WPF should now draw a red line around the textbox with an invalid value in it. Should you wonder where your validation message is, note that the default validation error template differ between WPF and Silverlight. Silverlight shows a nice validation message in a red warning box, WPF only draws the red line, no text or tooltip. This is something you get to implement as well. Check out this topic on StackOverflow: http://stackoverflow.com/questions/7434245/validation-error-style-in-wpf-similar-to-silverlight

    Hope this helps.

    JP

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.