Blogs

ViewModelLocatorBase

One of the more popular patterns for associating a view with it’s view model is the View Model Locator pattern. This is a special case of the Service Locator pattern, specifically tailored to XAML and MVVM. Update Controls supports this pattern with the ViewModelLocatorBase class.

imageThe View Model Locator pattern is view-first. When a view appears, it uses the view model locator to find its view model. Since the default navigation structure of most XAML stacks is view-first as well, the view model locator pattern is a natural choice.

A XAML application creates an instance of a view model locator and adds it to its resource dictionary. Then, it creates the first view. The view uses the view model locator to find its view model and sets its data context. When it comes time to navigate to a new view, the child view goes through the same process.

ViewModelLocator

The ViewModelLocator class has a property for each view model. Since it creates the view models, it also needs references to the model so it can call the constructors. These references are likely to include a selection model – an object responsible for keeping track of which item the user has selected. This comes in handy when the user can select something from the main view model, and then navigate to the child view. The selected item is passed into the constructor of the child view model.

public class ViewModelLocator : ViewModelLocatorBase
{
    private Document _document;
    private Selection _selection;

    public ViewModelLocator()
    {
        _document = LoadDocument();
        _selection = new Selection();
    }

    public object Main
    {
        get { return ViewModel(() => new MainViewModel(
_document, _selection)); } }
public object Child { get { return ViewModel(() => _selection.SelectedItem == null ? null : new ChildViewModel(_selection.SelectedItem)); } } private Document LoadDocument() { // TODO: Load your document here. Document document = new Document(); return document; } }

The ViewModelLocatorBase class in Update Controls provides the ViewModel method. This method takes a lambda expression that creates the view model. Update Controls will cache the view model, and make sure that the constructor is called again if the parameters change. For example, when the user selects a different item, Update Controls will construct a new child view model.

App.xaml

The application adds an instance of the view model locator to the resource dictionary. It references the namespace, and gives the object a key. This lets views find the locator.

<Application
    x:Class="MyCoolApp.App"
    xmlns:vm="clr-namespace:MyCoolApp.ViewModels">

    <!--Application Resources-->
    <Application.Resources>
        <vm:ViewModelLocator x:Key="Locator"/>
    </Application.Resources>
</Application>

There will be other things in the resource dictionary, including perhaps merged dictionaries. Just put the view model locator right inside the Application.Resources element.

DataContext

Each view sets its data context by binding to a property of the view model locator. It sets the binding source to the view model locator as a static resource.

<phone:PhoneApplicationPage
    x:Class="MyCoolApp.MainPage"
    DataContext="{Binding Main, Source={StaticResource Locator}}">

</phone:PhoneApplicationPage>

With this pattern, the view model locator is a singleton. Each view accesses a property of that single object to get its view model. The base class provided by Update Controls makes sure that a new view model is created if any of its constructor parameters change. This lets you set state in one view, and then depend upon that state as you navigate to another view. It’s a natural and straight-forward way of structuring your XAML applications.

MakeCommand

You can handle button-click events in the view model. Expose a property of type ICommand. Update Controls will implement the ICommand interface for you. Use the MakeCommand factory, and pass a delegate into the “Do” method.

public ICommand AddPerson
{
    get
    {
        return MakeCommand
            .Do(delegate
            {
                _selection.SelectedPerson = _document.NewPerson();
            });
    }
}

Some commands are not always enabled. Express the conditions under which your command is enabled by passing a lambda expression to the “When” method.

public ICommand DeletePerson
{
    get
    {
        return MakeCommand
            .When(() => _selection.SelectedPerson != null)
            .Do(delegate
            {
                _document.DeletePerson(_selection.SelectedPerson);
            });
    }
}

Data bind the property to the button’s Command. When the condition changes, the button will be enabled or disabled. And when the user clicks the button, if the condition is met, it will call the delegate in your view model.

ForView.Unwrap()

In the code behind of your view, the DataContext and all of the other bound objects that you will encounter are wrapped. This occurs whether you used the ViewModelLocatorBase class, returned them from the property of a wrapped object, or wrapped them yourself with ForView.Wrap(). To access the view model within the wrapper, you need to call ForView.Unwrap().

private void ListBox_SelectionChanged(
    object sender, SelectionChangedEventArgs e)
{
    foreach (object selected in e.AddedItems)
    {
        PersonViewModel viewModel =
            ForView.Unwrap<PersonViewModel>(selected);
        if (viewModel != null)
            viewModel.Select();
    }
}

You should always check the result. If you get back a null, then the wrapped object might not have been of the expected type.

IndependentList<T>

Independent<T> is used for single values. To track dependencies on collections, use IndependentList<T>. Use this as a field whenever you want to track changes to a collection.

public class Document
{
    private IndependentList<Person> _people = new IndependentList<Person>();
}

Expose the field as a read-only property of type IEnumerable<T>. Usually, you want your class to be in charge of what gets added to the list. IEnumerable<T> lets other classes enumerate the elements of the list, but not modify it.

public IEnumerable<Person> People
{
    get { return _people; }
}

IndependentList<T> supports all of the methods of List<T>. You can Add, Insert, Remove, etc. just as you are used to.

public Person NewPerson()
{
    Person person = new Person();
    _people.Add(person);
    return person;
}

public void DeletePerson(Person person)
{
    _people.Remove(person);
}

Any dependent properties that reference the list, even through the IEnumerable<T> interface, will take a dependency upon its contents. They will be updated when something is added to or removed from the list.

ForView.Wrap()

Update Controls will fire PropertyChanged events when values change. It does so through a wrapper that it puts around objects before giving them to the view. There are three ways to get this wrapper. First, if you use the ViewModelLocatorBase class, then the ViewModel method creates the wrapper. Second, any object you return from a view model will itself be wrapped. And third, if you are setting the DataContext in code, call the ForView.Wrap() method before assigning to the DataContext.

private void UserControl_Loaded(object sender, RoutedEventArgs e)
{
    Person model = new Person();
    PersonViewModel viewModel = new PersonViewModel(model);
    this.DataContext = ForView.Wrap(viewModel);
}

The wrapper will track the dependencies in each of the properties. It will fire PropertyChanged whenever a change occurs that impacts one of the dependent properties.

Any object that you return from the property of a wrapped object will itself be wrapped. There is, however, one exception. If your object implements INotifyPropertyChanged, then the wrapper is not created. Update Controls assumes that you are handling property change notification yourself, and therefore gets out of the way.

Independent<T>

Update Controls tracks dependencies within your application. The things that it depends upon are Independents. Independent<T> is used as a field whenever you want Update Controls to track changes.

Declare the Independent<T> as a private field. You can replace T with a simple type like “int” or “string”. Or you can replace it with an object type, like “Person”.

public class Person
{
    private Independent<string> _firstName = new Independent<string>();
    private Independent<string> _lastName = new Independent<string>();
    private Independent<Person> _spouse = new Independent<Person>();
}

Always initialize the field to a new Independent<T>. Forgetting this step will lead to null reference exceptions.

Expose the properties as the raw type T. The getter can return the Independent<T>, and it will be automatically converted to the raw type. But the setter has to assign to the Value property of the field.

public class Person
{
    private Independent<string> _firstName = new Independent<string>();
    private Independent<string> _lastName = new Independent<string>();
    private Independent<Person> _spouse = new Independent<Person>();

    public string FirstName
    {
        get { return _firstName; }
        set { _firstName.Value = value; }
    }

    public string LastName
    {
        get { return _lastName; }
        set { _lastName.Value = value; }
    }

    public Person Spouse
    {
        get { return _spouse; }
        set { _spouse.Value = value; }
    }
}

If you need to initialize the value of the field, pass the initial value to the Independent<T> constructor.

The Basics

This set of articles walks you through the most common scenarios of using Update Controls in a XAML-based application. These basics are applicable to WPF, Silverlight, Windows Phone, and Win RT development.

MVVM

A common pattern in XAML applications is Model-View-ViewModel (or MVVM). Update Controls supports this pattern.

To quick-start your application, add the UpdateControls.App package using NuGet. If you don’t yet have NuGet installed, you can get it from nuget.org. This package brings in the core UpdateControls package, and sets up the following structure:

  • Models
    • data models
    • selection models
  • ViewModels
    • top-level view models
    • headers
    • view model locator

Models

Data models are objects that you persist in your application. They will be saved to the database or local storage. These model objects represent the real-world concepts that your application is about.

public class Item
{
    private Independent<string> _name = new Independent<string>();

    public string Name
    {
        get { return _name; }
        set { _name.Value = value; }
    }
}

Selection models record the user’s point-of-view as they navigate through the system. These hold references to the model objects that the user selects in lists, and opens in secondary windows. They also hold any temporary data, like entries into text boxes, that haven’t been saved to the model, yet.

public class Selection
{
    private Independent<Item> _selectedItem = new Independent<Item>();

    public Item SelectedItem
    {
        get { return _selectedItem; }
        set { _selectedItem.Value = value; }
    }
}

Both data models and selection models use Independent<T> and IndependentList<T> fields. This lets Update Controls track dependencies upon model objects.

View Models

View models are simple classes that hold references to models. They expose properties for the purpose of data binding. These properties are implemented as pass-through methods, getting and setting data from the models.

public class ItemViewModel
{
    private readonly Item _item;

    public ItemViewModel(Item Item)
    {
        _item = Item;
    }

    public string Name
    {
        get { return _item.Name; }
        set { _item.Name = value; }
    }
}

The pass-through methods don’t have to be direct one-to-one accessors. In fact, they rarely are. It is far more common to alter the values on the way in and out. Here are some common types of alterations:

  • Return a default value if it hasn’t been set in the model.
  • Combine two or more model properties to display an aggregate.
  • Project child model objects into child view models.

That last one is very important. View models don’t return models. They return other view models. You never want your view to data bind directly against a model object. It should always have a view model in between.

public class MainViewModel
{
    private readonly Document _document;
    private readonly Selection _selection;

    public MainViewModel(Document document, Selection selection)
    {
        _document = document;
        _selection = selection;
    }

    public IEnumerable<ItemHeader> Items
    {
        get
        {
            return
                from item in _document.Items
                select new ItemHeader(item);
        }
    }
}

In addition to the top-level view models, you will often have headers. These are small view models created for the purpose of populating a list. The properties of a header are usually read-only, so you don’t create setters for them.

public class ItemHeader
{
    private readonly Item _item;

    public ItemHeader(Item Item)
    {
        _item = Item;
    }

    public Item Item
    {
        get { return _item; }
    }

    public string Name
    {
        get { return _item.Name ?? "<New Item>"; }
    }

    public override bool Equals(object obj)
    {
        if (obj == this)
            return true;
        ItemHeader that = obj as ItemHeader;
        if (that == null)
            return false;
        return Object.Equals(this._item, that._item);
    }

    public override int GetHashCode()
    {
        return _item.GetHashCode();
    }
}

A header always has to implement Equals and GetHashCode. These methods should compare two headers to see if they represent the same object. This allows Update Controls to preserve the selection and scroll position of a list even as the items in the list are changing. It also assists with binding the SelectedItem property. The SelectedItem should be equal to one element in the ItemsSource.

What's the merit of Update Controls over PostSharp or Notify Property Weaver

I received this question from Justin 袁 直.

Justin writes

Hello Michael

I've seen many ways of automatically implementing INotifyPropertyChange in Nuget, e.g. PostSharp.NotifyPropertyChanged or Notify Property Weaver. I see these methods also detects dependency relationships and fires propertychanged notification wisely.

Unlike applying an attribute, your method includes extra code in the Model class. So would you be so kind as to tell me what's the merit of your framework over the others?

Thank you very much

I respond

Great question.

The difference between Update Controls and the other libraries you mention is that Update Controls does its dependency analysis at run time. Notify Property Weaver and PostSharp both do this analysis at compile time.

Run-time dependency analysis has the advantage of detecting more cases. For example, if a view model calls a method through an interface, and that method references a property, compile-time analysis wouldn't detect it. Run-time analysis will.

Furthermore, as dependencies change, run-time analysis can adapt. Consider a view model property "if (a) return b else return c". While a is true, the property depends upon b. When it changes to false, the dependency switches to c. Compile-time analysis would lead to a dependency upon b and c at all times.

On the other hand, compile-time analysis has some advantages. It is easier to declare properties using attributes rather than writing code. And run-time analysis incurs some overhead in both time and memory.

I've found that the benefits of run-time analysis outweigh the drawbacks. But please use the technique that makes the most sense for your scenario.

Thank you.

Dependency-based validation

Windows Forms has a validation framework built in. WPF defined a new one. Silverlight refined it further. With every platform taking a slightly different approach to validation, it tends to get rather confusing.

Further confusing the issue is the fact that WPF actually has three options:

  • ValidatesOnExceptions
  • IDataErrorInfo (ValidatesOnDataErrors)
  • Data annotations

If you set ValidatesOnExceptions=True within your WPF {Binding}, you will get validation behavior when the setter throws an exception. If you implement IDataErrorInfo in your view model and set ValidatesOnDataErrors=True, then the view model decides when validation errors occur. And if you set data annotations on your view model properties (and put a bit of arcane code in your setters), then the attributes declaratively attach validation rules.

I recommend against ValidatesOnExceptions and data annotations, both for the same reason. If you throw an exception in the setter (which occurs in either option), then the user’s input is kept in the control. It never makes it to the view model where it can be stored. Indeed, the goal is not to store invalid data, but if you don’t store it temporarily, you can’t use it. It just stays in the TextBox or other control until the user fixes it. Your code doesn’t have access to that state, and therefore can’t help the user to resolve the issue. All the while, the control is in a different state than the view model, which makes me very nervous.

So that leaves IDataErrorInfo. In Silverlight, we now have it’s predecessor INotifyDataErrorInfo. Let’s see how to use this interface with Update Controls.

Single responsibility and validation

XAML validation takes place at the DataContext, which in MVVM is the ViewModel. But logically speaking, validation is a domain concept and therefore belongs in the Model. As a responsibility segregation pattern, MVVM is very sensitive to which side of the fence you choose.

Most MVVM implementations put state in the ViewModel. This gives you a place to store user input before it is validated, thus keeping the Model clean. An Update Controls app, however, does not put state in the ViewModel, since other ViewModels could depend upon it. On the plus side, you don't need a message bus to keep ViewModels in sync. On the minus side, you don't have a quarantine area for validation.

The result is that Update Controls guides you to a pattern in which you allow invalid data into the Model, and then present validation errors through the ViewModel. Don’t throw validation errors on input: take the invalid data into the model. Then let the model expose validation through dependent properties. This has the advantage of keeping the presentation responsibilities in the ViewModel, and the domain responsibilities in the Model. It has the disadvantage, however, of letting the Model get dirty. I find the tradeoff acceptable.

public class MyModel
{
    private static Regex ValidPhoneNumber = new Regex(@"\([0-9]{3}\) [0-9]{3}-[0-9]{4}");

    private Independent<string> _phoneNumber = new Independent<string>("");

    public string PhoneNumber
    {
        get { return _phoneNumber; }
        set { _phoneNumber.Value = value; }
    }

    public bool PhoneNumberIsValid
    {
        get { return ValidPhoneNumber.IsMatch(_phoneNumber); }
    }
}

This model has a PhoneNumber property, which can be set to any string. This property is backed by an Independent field so that Update Controls can track dependencies. The PhoneNumberIsValid property depends upon the phone number. When the phone number matches a regular expression, the validation property is true.

Dependent validation

Update Controls is a dependency tracking library. Validation errors displayed to the user are dependent upon the state of the model. One way to express a dependency is with the Dependent<T> field. Let’s set up a dependent boolean based on the phone number validity.

public class MyViewModel : ViewModelBase
{
    private MyModel _model;
    private Dependent<bool> _phoneNumberInvalid;

    public MyViewModel(MyModel model)
    {
        _model = model;

        // Create a dependent boolean that is true when the phone number is invalid.
        _phoneNumberInvalid = new Dependent<bool>(() => !_model.PhoneNumberIsValid);
    }

    public string PhoneNumber
    {
        get { return Get(() => _model.PhoneNumber); }
        set { _model.PhoneNumber = value; }
    }
}

The _phoneNumberInvalid field depends upon the PhoneNumberIsValid model, because that’s what the lambda expression references. When PhoneNumberIsValid changes (based on a change in PhoneNumber), the dependent goes out-of-date. We can hook this event to bring the dependent back up-to-date. We can’t force the update immediately, because things are still changing. Instead, we use the Dispatcher to schedule an update when the current user input event is finished.

// When the dependent goes out-of-date, bring it back up-to-date at the next opportunity.
_phoneNumberInvalid.DependentSentry.Invalidated += delegate
{
    Deployment.Current.Dispatcher.BeginInvoke(delegate
    {
        // Get the new value of the dependent. This brings it up-to-date.
        bool phoneNumberIsInvalid = _phoneNumberInvalid;
    });
};

A Dependent field begins its life out-of-date, so we have to force an update immediately upon construction. We can take this opportunity to save the initial state in a field.

// Get the initial value of the dependent. This brings it up-to-date.
_phoneNumberWasInvalid = _phoneNumberInvalid;

Now we have all the hooks we need to implement INotifyDataErrorInfo. When the phone number validation state changes, we fire the ErrorsChanged event.

// When the dependent goes out-of-date, bring it back up-to-date at the next opportunity.
_phoneNumberInvalid.DependentSentry.Invalidated += delegate
{
    Deployment.Current.Dispatcher.BeginInvoke(delegate
    {
        // Get the new value of the dependent. This brings it up-to-date.
        bool phoneNumberIsInvalid = _phoneNumberInvalid;

        // Fire the event if the status has changed.
        if (phoneNumberIsInvalid != _phoneNumberWasInvalid && ErrorsChanged != null)
            ErrorsChanged(this, new DataErrorsChangedEventArgs("PhoneNumber"));

        _phoneNumberWasInvalid = phoneNumberIsInvalid;
    });
};

We finish the interface out with the GetErrors and HasErrors methods.

public IEnumerable GetErrors(string propertyName)
{
    if (propertyName == "PhoneNumber")
        if (_phoneNumberInvalid)
            yield return "Please enter (###) ###-####";
}

public bool HasErrors
{
    get { return _phoneNumberInvalid; }
}

Validation is the responsibility of the Model. Presentation of errors is a ViewModel responsibility. Like all ViewModel behavior in MVVM, error presentation depends upon the model. We just have to be explicit about it.

From this code, I can see the beginnings of a reusable validation framework within Update Controls. ForView.Wrap could perform all of the steps that we did here. It would just need help determining validation errors for each property. Perhaps a Caliburn-like convention-over-configuration pattern is in order. Please leave a comment if you agree, disagree, or are willing to contribute to the project.

Syndicate content