Input Validation and UI Exceptions with MVVM Light

I have worked on several Silverlight and Windows Phone 7 projects but only recently began my first WPF application. While researching the best way to perform input validation in WPF, I learned there are really two types of invalid data – data that fails the business rules implemented (preferably) in the business objects and invalid data which throws an exception in the UI as a result of the binding pipeline being unable to convert from the target data type used in the control to the source data type in the ViewModel. For instance, a TextBox bound to an “Age” property of type Int32 will throw an exception in the UI if the user enters a value in the TextBox that cannot be converted to an integer.

Karl Shifflett and Josh Smith have each written about how to handle such UI exceptions. Josh’s article describes wrapping your Model object in a ViewModel whose data types match those of the target bindings. This effectively prevents these types of exceptions from being thrown in the UI and allows the IDataErrorInfo implementation in the wrapper ViewModel to handle the input validation and return custom error messages when problems are found.

Karl’s article describes a solution which is much easier to implement in that most of the code is contained in two base classes and all of the errors are stored in the ViewModel. This makes it easy to disable a “Save” button if the data in the ViewModel is invalid for any reason. However, the drawback is that you don’t get custom error messages for the validation errors generated by exceptions thrown in the UI.

I think each of these options have their place. It is up the the developer to decide which path to take based on the type and size of application being written. For my application, I decided I needed the easier implementation path and felt I could live without custom error messages for UI exceptions.

The next step for me was to find the best way to integrate Karl’s solution with Laurent Bugnion’s excellent MVVM Light framework. I have used MVVM Light on other applications and appreciate it’s simplicity and focus on the essential services needed for a clean MVVM solution. Thankfully, Laurent makes the MVVM Light code available on CodePlex. I added his code to my solution and then tweaked it slightly to include Karl’s validation solution.

I first modified the ViewModelBase.cs class by adding the “partial” keyword allowing me to extend the class in another file without making further modifications to the original. This should make upgrading to future versions of MVVM Light easier.

public abstract partial class ViewModelBase : INotifyPropertyChanged, ICleanup, IDisposable

I then added a new file to the GalaSoft.MvvmLight project called “ViewModelBase.partial.cs”. In it I added the code from Karl Shifflett’s solution to add, remove, and clear UI validation errors in the ViewModel. I also decided to add a virtual property called “IsValid” that can be overridden in derived classes to implement the logic to determine if the ViewModel is eligible to be saved. Here is a sample of my slightly modified version of Karl’s code.

namespace GalaSoft.MvvmLight
    public abstract partial class ViewModelBase
        private Dictionary<string, UIValidationError> _objUIValidationErrorDictionary = new Dictionary<string, UIValidationError>();
        public int UIValidationErrorCount { get { return _objUIValidationErrorDictionary.Count; } } 
        public string UIValidationErrorUserMessages { get { StringBuilder sb = new StringBuilder(1024); foreach (KeyValuePair<string, UIValidationError> kvp in _objUIValidationErrorDictionary) { sb.AppendLine(String.Format("{0} has an invalid entry.", kvp.Value.PropertyName)); } return sb.ToString(); } } 
        public virtual bool IsValid { get { return true; } } public void AddUIValidationError(UIValidationError e) { _objUIValidationErrorDictionary.Add(e.Key, e); RaisePropertyChanged("UIValidationErrorUserMessages"); RaisePropertyChanged("UIValidationErrorCount"); RaisePropertyChanged("IsValid"); } 
        protected void ClearUIValidationErrors() { _objUIValidationErrorDictionary.Clear(); RaisePropertyChanged("UIValidationErrorUserMessages"); RaisePropertyChanged("UIValidationErrorCount"); RaisePropertyChanged("IsValid"); } public void RemoveUIValidationError(UIValidationError e) { _objUIValidationErrorDictionary.Remove(e.Key); RaisePropertyChanged("UIValidationErrorUserMessages"); RaisePropertyChanged("UIValidationErrorCount"); RaisePropertyChanged("IsValid"); } } }

I then added Karl’s UIValidationError.cs file to the GalaSoft.MvvmLight project, implemented IDataErrorInfo in my Model classes, and had all my Views inherit from Karl’s ViewBase class.

Now all of my errors are stored in the ViewModel and I can prevent invalid changes from being saved regardless of where they originated – all within the tight and tidy world of MVVM Light.

I should note that the translation of Karl’s code from VB to C# is my own and all errors in the translation are mine and not his.

Many thanks to Karl Shifflett and Laurent Bugnion for making their code available to the community.

Author image
About Brice Wilson