The problem of the Windows Phone 7 ApplicationBar and not (yet) updated Bindings

As a MVVM enthusiast I’m trying to use MVVM as much as possible, but not for things that are almost impossible to do with MVVM. But simple things, like a TextBox Text property is always bound to a ViewModel’s property. That’s something that works very well…until you start having ApplicationBar buttons and menu items.

A lot of people already know that the ApplicationBar is something special, it’s not just a control like other stuff in your application. When clicking a button on the ApplicationBar the Binding is not yet updated. This is basically because the focus which is on the TextBox for example won’t be changed when clicking ApplicationBar buttons. This is different compared to normal buttons that you put somewhere on your page.

The Solution?

I’ve read different solutions on the web. For example, force focus on a different control by calling the Focus method on a Control. While this is working, I found a technically nicer solution. By getting the Binding of the current focused control and updating that binding.

I wrote a small helper class that implements this Binding updating.

public static class ApplicationBarHelper
{
    public static void UpdateBindingOnFocussedControl()
    {
        object focusedElement = FocusManager.GetFocusedElement();
        if (focusedElement != null && focusedElement is TextBox)
        {
            var binding = (focusedElement as TextBox).GetBindingExpression(TextBox.TextProperty);
            if (binding != null)
                binding.UpdateSource();
        }
    } 
}

The first thing you do in the Event handlers for the ApplicationBar Click events is call.

ApplicationBarHelper.UpdateBindingOnFocussedControl();

What about the BindableApplicationBar?

A lot of use MVVM enthusiasts are using the BindableApplicationBar that’s part of the Phone7.Fx library. Can we use this in combination with the BindableApplicationBar? Yes we can, actually the best way would be to have this integrated with the BindableApplicationBar itself. I have just downloaded the source and manipulated two methods in two classes.

public class BindableApplicationBarIconButton : FrameworkElement, IApplicationBarIconButton
{
    // Other code that hasn't been changed in this class.

    void ApplicationBarIconButtonClick(object sender, EventArgs e)
    {
        ApplicationBarHelper.UpdateBindingOnFocussedControl();
        if (Command != null && CommandParameter != null)
            Command.Execute(CommandParameter);
        else if (Command != null)
            Command.Execute(CommandParameterValue);
        if (Click != null)
            Click(this, e);
    }
}

public class BindableApplicationBarMenuItem : FrameworkElement, IApplicationBarMenuItem
{
    // Other code that hasn't been changed in this class.

    private void ApplicationBarMenuItemClick(object sender, EventArgs e)
    {
        ApplicationBarHelper.UpdateBindingOnFocussedControl();
        if (Command != null && CommandParameter != null)
            Command.Execute(CommandParameter);
        else if (Command != null)
            Command.Execute(CommandParameterValue);
        if (Click != null)
            Click(this, e);
    }
}

Validating our ViewModel

One of the key features that need to be implemented in a Line of Business application. Although Silverlight supports validation very well it’s not that easy compared to enabling Data Binding your ViewModel.

When we want our ViewModel to be fully Data Bindable we implement the INotifyPropertyChanged interface. It’s really an easy interface with an Event that needs to be called when the value of a property has changed. A lot of people don’t implement this interface themselves but use a framework like MVVM Light. I’m using that as well.

To make the validation work in a similar way we will have to implement INotifyDataErrorInfo. This is similar but I haven’t found a framework implementing it for me, so I wrote my own implementation of a ViewModelBase that both supports INotifyPropertyChanged and INotifyDataErrorInfo.

INotifyDataErrorInfo interface

Declaring the validation rules

Now that we have a ViewModel which supports validation we need to use it in our ViewModels. Let’s say that we have a LoginViewModel, which requires a Username and Password to be filled in.

So we need to declare our properties Username and Password as Required. Besides that we also want the message text to be changed to something different than the default, so we set the ErrorMessage property.

public class Login : ViewModelBase
{
    private string _password;
    private bool _rememberMe;
    private string _userName;

    [Required(AllowEmptyStrings = false, ErrorMessage = "Username is required")]
    public string UserName
    {
        get { return _userName; }
        set
        {
            if (_userName != value)
            {
                ValidateProperty("UserName", value);
                _userName = value;
                base.RaisePropertyChanged("UserName");
            }
        }
    }

    [Required(AllowEmptyStrings = false, ErrorMessage = "Password is required")]
    public string Password
    {
        get { return _password; }
        set
        {
            if (_password != value)
            {
                ValidateProperty("Password", value);
                _password = value;
                base.RaisePropertyChanged("Password");
            }
        }
    }

    public bool RememberMe
    {
        get { return _rememberMe; }
        set
        {
            if (_rememberMe != value)
            {
                _rememberMe = value;
                base.RaisePropertyChanged("RememberMe");
            }
        }
    }
}

Alright this was the usage of one of the most rudimentary validation types. A small overview of all the different supported validation types.

- RequiredAttribute used to check if a property has a value and will return invalid in case of null, empty string, or only white space characters.

- DataTypeAttribute like it’s name the data type validator validates a value against certain ‘data types’: DateTime, Date, Time, Duration, PhoneNumber, Currency, Text, Html, MultilineText, EmailAddress, Password, Url, ImageUrl.

- RangeAttribute is used to validate int, decimal and double values which need to fall between certain min and max values.

- RegularExpressionAttribute can be used for more advanced scenario’s where you can write the full regular expression which should be used to validate against.

- StringLengthAttribute can be used to validate the length of a string in characters, you can specify both the maximum length and minimum length, but one of them is also possible. Be aware that a null value will be seen as valid!

- CustomValidationAttribute used in the most complex validation scenario’s. The CustomValidationAttribute needs to be used in conjunction with a static method which returns a ValidationResult. This static method can be used to implement your very complex validation rules.

And if the above validation types don’t fit, you can always derive from the ValidationAttribute and write your own implementation. It’s important to know that in case of a null-value the properties won’t be validated. This is something that’s not always helpful, specially in case of the CustomValidation where you want to implement a conditional required field validation. The Required validation does get fired in case of null-value.

Tools to enforce our ValidationAttributes

We have the Validator class that has a few static methods that can validate an object that’s decorated with ValidationAttributes. There is a method for validating a single property, which is handy in case you want immediate feedback on the change of the value of the property. And there is of course a method for validating the full object.

Time to implement the INotifyDataErrorInfo

To give everyone a clear understanding the implementation of INotifyDataErrorInfo will be a step by step implementation. If you’re only interested in the solution, you can of course skip this, and go to the end of the article.

ErrorsChanged event:

To start with the easy stuff, we need a way to notify that there are some errors. So besides the ErrorsChanged event we need a method to fire ErrorsChanged.

public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;

protected void NotifyErrorsChanged(string propertyName)
{
    if (ErrorsChanged != null)
        ErrorsChanged(this, new DataErrorsChangedEventArgs(propertyName));
}

GetErrors method and HasErrors property:

The GetErrors method needs to return errors for a specific property, so what we need is someway to store the errors. To store the errors I added a dictionary where the key would be the property name and the value would be a list of errror messages. GetErrors is in that case easily implemented by just returning data based on the key.

Further more the HasErrors is a matter of looking whether or not the dictionary has any data.

private readonly IDictionary<string, IList<string>> _errors = new Dictionary<string, IList<string>>();

public IEnumerable GetErrors(string propertyName)
{
    if (_errors.ContainsKey(propertyName))
    {
        IList<string> propertyErrors = _errors[propertyName];
        foreach (string propertyError in propertyErrors)
        {
            yield return propertyError;
        }
    }
    yield break;
}

public bool HasErrors
{
    get { return _errors.Count > 0; }
}

But how do we get some errors in the Dictionary?

As you have seen the implementation of INotifyDataErrorInfo is really straightforward, but we don’t do any validation yet. One of the scenario’s that’s very neat I would say is the ability to immediately give feedback to our users about validation problems. So when the value of a property is set (through two way binding for example) we want to validate immediately.

That’s not particularly difficult if we compare it to the normal MVVM property signature we only need to Validate a property. To keep it similar to the MVVM Light RaisePropertyChanged, we have to include the property name and value as well.

[Required(AllowEmptyStrings = false, ErrorMessage = "Username is required")]
public string UserName
{
    get { return _userName; }
    set
    {
        if (_userName != value)
        {
            ValidateProperty("UserName", value);
            _userName = value;
            base.RaisePropertyChanged("UserName");
        }
    }
}

Now we of course want to have an implementation for ValidateProperty. This implementation needs to validate only a specific property value against the rules for that property. We can make use of the Validator class that implements the actual checking against the validation rules. Together with two helper methods to add and remove validation messages from Errors collection we have the following code. We make use of the Validator to validate a property, and after we have the results we notify that Errors have been changed.

protected void ValidateProperty(string propertyName, object value)
{
    ViewModelBase objectToValidate = this;
    var results = new List<ValidationResult>();
    bool isValid = Validator.TryValidateProperty(
        value,
        new ValidationContext(objectToValidate, null, null)
            {
                MemberName = propertyName
            },
        results);

    if (isValid)
        RemoveErrorsForProperty(propertyName);
    else
        AddErrorsForProperty(propertyName, results);

    NotifyErrorsChanged(propertyName);
}

private void AddErrorsForProperty(string propertyName, IEnumerable<ValidationResult> validationResults)
{
    RemoveErrorsForProperty(propertyName);
    _errors.Add(propertyName, validationResults.Select(vr => vr.ErrorMessage).ToList());
}

private void RemoveErrorsForProperty(string propertyName)
{
    if (_errors.ContainsKey(propertyName))
        _errors.Remove(propertyName);
}

This works very well in the conjunction with the View, but somehow we also need to check if the full ViewModel is valid. This is especially important in when we hit for example the buttons that need to save our data to a “repository”. Besides the Validator.TryValidateProperty there also is a Validator.TryValidateObject. So let’s write a similar operation as the ValidateProperty, but now something we are able to use on Commands, so it needs to return a boolean where or not the ViewModel is valid. Again most of the magic is in the Validator.TryValidateObject, afterwards we split the full list of ValidationResults per property, to give feedback to our View.

public bool ValidateObject()
{
    ViewModelBase objectToValidate = this;
    _errors.Clear();
    var results = new List<ValidationResult>();
    bool isValid = Validator.TryValidateObject(objectToValidate,
                                                new ValidationContext(objectToValidate, null, null), results,
                                                true);
    if (!isValid)
    {
        IEnumerable<string> propertiesWithMessage = results.SelectMany(vr => vr.MemberNames);
        foreach (string property in propertiesWithMessage)
        {
            IEnumerable<ValidationResult> messages = results.Where(vr => vr.MemberNames.Contains(property));
            AddErrorsForProperty(property, messages);
            NotifyErrorsChanged(property);
        }
    }
    return isValid;
}

Problem to solve

Next is a problem we will need to solve. When the value of a property is null none of the validation attributes will be enforced, except the RequiredAttribute. This is really a problem for our CustomValidationAttribute when we implement a rule that should do something special in case of a null value.

After a better investigation I found out that all validation attributes are enforced when we validate a single property with the Validator class. Which isn’t happening when we use the full object validation implemented by the Validator class.

So why not solve it ourselves, by executing the Validate property method on all properties? Good idea, so I implemented it in our ViewModelBase. It’s pretty straightforward the first get all the properties, and then filter these to get the properties which have ValidationAttributes applied. End will be the call to validate the property for that specific value in line 12.

public bool ValidateObject()
{
    ViewModelBase objectToValidate = this;
    _errors.Clear();
    Type objectType = objectToValidate.GetType();
    PropertyInfo[] properties = objectType.GetProperties();
    foreach (PropertyInfo property in properties)
    {
        if (property.GetCustomAttributes(typeof (ValidationAttribute), true).Any())
        {
            object value = property.GetValue(objectToValidate, null);
            ValidateProperty(property.Name, value);
        }
    }

    return !HasErrors;
}

Full source

As always the full source of my ViewModelBase, which enhances the functionality of the MVVM Light ViewModelBase.

public abstract class ViewModelBase : GalaSoft.MvvmLight.ViewModelBase, INotifyDataErrorInfo
{
    private readonly IDictionary<string, IList<string>> _errors = new Dictionary<string, IList<string>>();

    protected ViewModelBase()
    {
    }

    protected ViewModelBase(IMessenger messenger)
        : base(messenger)
    {
    }

    #region INotifyDataErrorInfo Members

    public IEnumerable GetErrors(string propertyName)
    {
        if (_errors.ContainsKey(propertyName))
        {
            IList<string> propertyErrors = _errors[propertyName];
            foreach (string propertyError in propertyErrors)
            {
                yield return propertyError;
            }
        }
        yield break;
    }

    public bool HasErrors
    {
        get { return _errors.Count > 0; }
    }

    public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;

    #endregion

    protected void NotifyErrorsChanged(string propertyName)
    {
        if (ErrorsChanged != null)
            ErrorsChanged(this, new DataErrorsChangedEventArgs(propertyName));
    }

    protected void ValidateProperty(string propertyName, object value)
    {
        ViewModelBase objectToValidate = this;
        var results = new List<ValidationResult>();
        bool isValid = Validator.TryValidateProperty(
            value,
            new ValidationContext(objectToValidate, null, null)
                {
                    MemberName = propertyName
                },
            results);

        if (isValid)
            RemoveErrorsForProperty(propertyName);
        else
            AddErrorsForProperty(propertyName, results);

        NotifyErrorsChanged(propertyName);
    }

    private void AddErrorsForProperty(string propertyName, IEnumerable<ValidationResult> validationResults)
    {
        RemoveErrorsForProperty(propertyName);
        _errors.Add(propertyName, validationResults.Select(vr => vr.ErrorMessage).ToList());
    }

    private void RemoveErrorsForProperty(string propertyName)
    {
        if (_errors.ContainsKey(propertyName))
            _errors.Remove(propertyName);
    }

    public bool ValidateObject()
    {
        ViewModelBase objectToValidate = this;
        _errors.Clear();
        Type objectType = objectToValidate.GetType();
        PropertyInfo[] properties = objectType.GetProperties();
        foreach (PropertyInfo property in properties)
        {
            if (property.GetCustomAttributes(typeof (ValidationAttribute), true).Any())
            {
                object value = property.GetValue(objectToValidate, null);
                ValidateProperty(property.Name, value);
            }
        }

        return !HasErrors;
    }
}

MeXperience – Step 2 – Architecture and more

Besides the purpose of the application itself, I want to make sure I expand my knowledge on Silverlight. This would be especially on the architecture of Silverlight applications. Architecture - MVVM I’ve read quite a lot of articles on MVVM, but there weren’t many article series that were as complete as the series on RIA, MEF and MVVM by Shawn Wildermuth (1,2,3,4). I have no intend to write an article or series on MVVM because it’s not really in my fingers yet. But to know more on MVVM please read the fantastic series by Shawn. But then again my intend is to make use of MVVM for MeXperience. The idea is to introduce two ViewModels (please let me know if you’d advice a different setup for ViewModels). 1. The ExperienceFilterViewModel, which supports showing all experience-tags and the ability to form a filter. 2. The ExperienceViewModel, which has control over all experience-parts that are found in the data store and can interact independent from the filter but can have filters applied as well. Because I chose to use the articles by Shawn as my knowledge base for MVVM, I will make use of the same components: MEF and MVVM Light Toolkit. If you have suggestions for other libraries, I’m interested, but this will be my start. Architecture – Pipes and Filters For the purpose of filtering the experience I want to introduce a Pipes and Filters design pattern. I know it’s not absolutely necessary but it makes sense for this purpose. Architecture – Experience Data Store It’s very standard to give an application a database for it’s data store. But to be honest there are many situation where a database isn’t the best choice. So in this occasion I think an xml file containing all the experience information will do. For now MeXperience will only be about the presentation of the experience. Maybe some time in the future there will be an application to edit this xml file. User Interface Components I’ve searched around the web (being aware of some licenses I won during Silverlight Control Builder Contest) for some User Interface components that could really help implementing the User Interface that I proposed in my prototype in the first part of my series. MeXperience Basic ViewMeXperience Detailed View The first piece of User Interface that I want to cover is the TagCloud. But when I search on Google, I first find a component on Codeplex which has tight integration with WCF, second result is an article from my own hand (July 2008), third is the very nice 3D-Tagcloud by Peter Gerritsen. But in the end all that looks like the best suitable component is the Silverlight Tag Cloud by Infragistics (I’m lucky to have the license). Further on the experience table-tile-view thingy. After some investigation I’m sure, it’s called a Tile View. Both Infragistics and Telerik have such a control. But because I already found a Tag Cloud by Infragistics I will use the Infragistics controls. Hope this will be a good choice.