Reply to comment

List and detail

Many applications use the list/detail UI idiom. The user selects an item in a list. The item appears in a detail pane. This is easy to do in Update Controls using the Navigation Model pattern.

List property

First, we need a property in our view model that returns a list of items. Each item will itself be a view model. We wrap each data model object in a summary view model using a linq select statement.

public IEnumerable<OrderSummaryViewModel> PendingOrders
{
    get
    {
        return
            from o in _company.PendingOrders
            select new OrderSummaryViewModel(o);
    }
}

Next, we data bind this property to a list box. Bind ItemsSource to the list. Use an ItemTemplate to render each item.

<ListBox ItemTemplate="{DynamicResource OrderSummaryViewModelTemplate}" ItemsSource="{Binding PendingOrders}"/>

Selected item property

Then, we need a property for the selected item. This property will be the same type as the items in the list.

public OrderSummaryViewModel SelectedOrderSummary
{
    get
    {
        return _navigation.SelectedOrder == null
            ? null
            : new OrderSummaryViewModel(_navigation.SelectedOrder);
    }
    set
    {
        _navigation.SelectedOrder = value == null
            ? null
            : value.Order;
    }
}

Since the first property was IEnumerable of OrderSummaryViewModel, the second needs to be OrderSummaryViewModel. However, we don’t want to store the view model type in the navigation model. Instead, we store the data model.

private Order _selectedOrder;

#region Independent properties
// Generated by Update Controls --------------------------------
private Independent _indSelectedOrder = new Independent();

public Order SelectedOrder
{
    get { _indSelectedOrder.OnGet(); return _selectedOrder; }
    set { _indSelectedOrder.OnSet(); _selectedOrder = value; }
}
// End generated code --------------------------------
#endregion

Bind this new property to the SelectedItem of the ListBox.

<ListBox ItemTemplate="{DynamicResource OrderSummaryViewModelTemplate}" ItemsSource="{Binding PendingOrders}" SelectedItem="{Bidning SelectedOrderSummary}"/>

Equals and GetHashCode

Now the trick is that the selected order has to be equal to one of the items in the list. Since we are creating new OrderSummaryViewModels in each of these properties, they will never be the same object. So we have to implement Equals ourselves.

public override bool Equals(object obj)
{
    if (obj == this)
        return true;
    OrderSummaryViewModel that = obj as OrderSummaryViewModel;
    if (that == null)
        return false;
    return this._order == that._order;
}

Whenever we implement Equals, we must also implement GetHashCode.

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

Detail property

Finally, we can expose the selected order as a detail property. We wrap the order in a different view model, one specifically tailored to editing.

public OrderDetailsViewModel SelectedOrderDetails
{
    get
    {
        return _navigation.SelectedOrder == null
            ? null
            : new OrderDetailsViewModel(_navigation.SelectedOrder);
    }
}

The benefit of this pattern is that you can change the selection programmatically without talking directly to the view. Both the selection and the details will update. I like to set the selected order to a new order when it is first created. Sometimes there are other controls that need to bind to or change the selection themselves. For example, a button might delete the selected item. Simply bind those other controls to the same navigation model, and they will all work together.

Reply

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