Reply to comment

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.

Reply

By submitting this form, you accept the Mollom privacy policy.