IBinder and Convention over Configuration

Prerequisites

  1. Obtain and Build the Code
  2. Setting Up a Project

Referenced Assemblies

  • Caliburn.Core
  • Caliburn.PresentationFramework
  • Microsoft.Practices.ServiceLocation

Explanation

IBinder plays an important part in the View.Model attached property lifecycle. When this property is set, after a view is located using the IViewStrategy, the IBinder "connects" the View and the ViewModel.

DefaultBinder

The default implementation, DefaultBinder, automatically set's the View's Action.Target to the model and stores the ViewMetadata if the Model is an IMetadtaContainer. It also wires up the IViewAware events, if the model implements this interface. In addition, you can enable MessageConventions and BindingConventions on the default implementation.

Message Conventions

To enable this feature, call EnableMessageConventions. Doing so will cause the binder to inspect the model and the View and attempt to automatically wire Actions based on control name and action name. It will also inspect the parameters of your VM's actions and attempt to wire up the message parameters appropriately. For this to work, your parameter names must match the UI elements names or they must have the same name as a special value, such as dataContext or eventArgs. The action mechanism also has a convention of wiring IPreProcessor filters for methods following the pattern Can + ActionName. It also checks for properties with the same pattern and wires them to IsEnabled. Below is an example showing the Xaml and VM which would be bound using the default trigger for button:

<StackPanel>
  <Button x:Name="Save" />
  <Button x:Name="Cancel" />
</StackPanel>

public class MyViewModel
{
  public bool CanSave  //Bound to Button.IsEnabled
  {
    get { return true; }
  }
  
  public void Save(SomeType dataContext)  //Called on Button.Click.  Button.DataContext is passed in as a parameter.
  {
    //do something
  }

  public bool CanCancel() //Turned into an IPreProcessor filter.
  {
    return true;
  }

  public void Cancel()  //Called on Button.Click
  {
    //do something
  }
}

Binding Conventions

To enable this feature, call EnableBindingConventions. Doing so will cause the binder to inspect models to see if they are implementors of IPresenter and its cohorts. If so, it will attempt to wire up ContentControls, ItemsControls and Selectors in your UI in such a was as to represent the presenter hierarchy automatically. Here's how it works:
  1. If your model implements IPresenterHost:
    1. We look to see if there is a control named "CurrentPresenter" and if found, it's Content property is bound to the VM's CurrentPresenter property using View.Model.
    2. We look to see if there is a control named "PresenterHost" and if found, we wire its ItemsSource to the Presenters property of the WM. We then generate a DataTemplate for each item, which uses a ContentControl with View.Model to connect each child presenter. Finally, if the control is a Selector, we bind the SelectedItem property to the VM's CurrentPresenter.
  2. If your model has public properties of type IPresenter:
    1. We locate a control with the same name as the property. If found, we bind it to the property using View.Model.

Customization

As always, you can make your own implementation of IBinder and replace the default version provided by Caliburn. An easier path would be to override one or more of the following methods on the default implementation: AttachTo, ApplyMessageConventions and ApplyBindingConventions.

Futures

Version 2 of Caliburn will expand the capabilities of DefaultBinder and its conventions to cover a larger number of databinding scenarios.

Last edited Oct 23, 2009 at 6:53 PM by EisenbergEffect, version 12