Creating a view model with a model and mappings

During of the use of the MVVM pattern, we noticed that lots and lots of developers have a model, and map the values of the model to all properties of the view model. When the UI closes, the developers map all the properties back to the model. All this redundant code is not necessary when using the view models of Catel.

In Catel, we have created attributes that allow you to define a property as a model. A model is a property that a part of the view model represents to the user. A view model might have multiple models if it is a combination of several models.

To use the mapping features, the following attributes are very important:

  • ModelAttribute - declare a model in a view model
  • ViewModelToModelAttribute - declare a mapping from a view model property to a model property

Code snippets

  • vm - declare a view model
  • vmpropmodel - declare a property as model on a view model
  • vmpropviewmodeltomodel - declare a property as a pass-through property on a view model"

Explanation

Defining a model is very simple, you only have to decorate your property with the ModelAttribute:

/// <summary>
/// Gets or sets the shop.
/// </summary>
[Model]
public IShop Shop
{
    get { return GetValue<IShop>(ShopProperty); }
    private set { SetValue(ShopProperty, value); }
}

/// <summary>
/// Register the Shop property so it is known in the class.
/// </summary>
public static readonly PropertyData ShopProperty = RegisterProperty("Shop", typeof(IShop));

Using the ModelAttribute is very powerful. Basically, this is the extended functionality in the view model. If the model supports IEditableObject, BeginEdit is automatically called in the initialization of the view model. When the view model is canceled, the CancelEdit is called so the changes are undone.

When a model is defined, it is possible to use the ViewModelToModelAttribute, as you can see in the code below:

/// <summary>
/// Gets or sets the name of the shop.
/// </summary>
[ViewModelToModel("Shop")]
public string Name
{
    get { return GetValue<string>(NameProperty); }
    set { SetValue(NameProperty, value); }
}

/// <summary>
/// Register the Name property so it is known in the class.
/// </summary>
public static readonly PropertyData NameProperty = RegisterProperty("Name", typeof(string));

The ViewModelToModelAttribute in the code example above automatically maps the view model Name property to the Shop.Name property. This way, you don’t have to manually map the values from and to the model. Another nice effect is that the view model automatically validates all objects defined using the ModelAttribute, and all field and business errors mapped are automatically mapped to the view model.

Summarized, the model and ViewModelToModel attributes make sure no duplicate validation and no manual mappings are required.