Presentation Patterns

Presentation Model

MVVM

MVP

#### Passive View * “A screen and components with all application specific behavior extracted into a controller so that the widgets have their state controlled entirely by controller.” * solves the problem of testability. * handles this by reducing the behaviour of the UI components to the absolute minimum by using a controller that not just handles responses to user events, but also does all the updating of the view.

Supervising Controller

INotifyPropertyChanged

This interface exposes a single event that screen widgets subscribe to. The event should be raised when any properties on the subject have changed, this signals the UI to synchronize with the current state of the ViewModel. There are a few things that I don’t like about common usage of this interface and that is hard coded string sprinkled across your source code. this is not refactoring friendly and does not provide you with any sort of compile time errors when an incorrect property name is provided. This is an implementation of the Observer design pattern.

Observer

“The Observer Pattern defines a one-to-many dependency between objects so that when one object changes state, all of its dependents are notified and updated automatically.” - Head First Design Patterns

Example 1. Using Inheritance

public interface INotifyPropertyChanged
  {
    event PropertyChangedEventHandler PropertyChanged;
  }

  public abstract class Observable<T> : INotifyPropertyChanged
  {
    protected void update(params Expression<Func<T, object>>[] properties)
    {
      properties.each(x =>
      {
        PropertyChanged(this, new PropertyChangedEventArgs(x.pick_property().Name));
      });
    }

    public event PropertyChangedEventHandler PropertyChanged = (o, e) => {};
  }

  public class ViewModel : Observable<ViewModel>
  {
    public string FirstName 
    {
      get{ return firstName; }
      set
      { 
        return firstName;
        update(x => x.FirstName);
      }
    }
    string firstName;
  }

Example 2. Using Composition

public abstract class Observable<T> : INotifyPropertyChanged
  {
    protected void update(params Expression<Func<T, object>>[] properties)
    {
      properties.each(x =>
      {
        propertyChanged(this, new PropertyChangedEventArgs(x.pick_property().Name));
      });
    }

    PropertyChangedEventHandler propertyChanged;
  }

  public class ViewModel 
  {
    public ViewModel()
    {
      observable = new Observable<ViewModel>(this.ProperChanged);
    }

    public string FirstName 
    {
      get{ return firstName; }
      set{ 
        return firstName;
        observable.update(x => x.FirstName);
      }
    }

    public event PropertyChangedEventHandler PropertyChanged = (o, e) => {};
    Observable<ViewModel> observable;
  }

INotifyCollectionChanged

When binding a screen widget to a collection you can create a collection that implements this interface to signal the widget when items are added or removed. When you add a new item to the collection raise the CollectionChanged event to signal the UI to rebind to the collection.

The built in [ObservableCollection](http://msdn.microsoft.com/en-us/library/ms668604.aspx) implements this interface and takes care of raising the changed event when items are added or removed from the collection. When binding to a large number of items, it can be helpful to suspend publishing of the changed event then batch the adding of those items then continue raising the changed event.

public interface INotifyCollectionChanged
  {
      event NotifyCollectionChangedEventHandler CollectionChanged;
  }

ICommand

This interface defines an action that screen widgets can invoke when they are activated. The simplest example is a Button. When a button is clicked it will execute the command that it is bound to. If the command cannot be executed then the button will become disabled.

This is an implementation of the Command Pattern and the Specification Pattern.

Command:

“The Command Pattern encapsulates a request as an object, thereby letting you parameterize other objects with different requests, queue or log requests, and support undoable operations.” - Head First Design Patterns

Specification:

“In computer programming, the specification pattern is a particular software design pattern, whereby business logic can be recombined by chaining the business logic together using boolean logic.”

This synchronization is done via this interface. When a condition in the application changes the ability for a command to be executed, the command must raise the CanExecuteChanged event to signal the UI to check if the command can be executed.

public interface ICommand
  {
    void Execute(object parameter);
    void CanExecute(object parameter);
    event EventHandler CanExecuteChanged;
  }

  public class SimpleCommand : ICommand
  {
    Action command;
    Func<bool> predicate;

    public SimpleCommand(Action command): this(command, () => true) { }

    public SimpleCommand(Action command, Func<bool> predicate)
    {
      this.command = command;
      this.predicate = predicate;
    }

    public void Execute(object parameter)
    {
      command();
    }

    public bool CanExecute(object parameter)
    {
      return predicate();
    }

    public event EventHandler CanExecuteChanged = (o,e)=>{};
  }

  <Button Command="{Binding Path=SaveCommand}">Save</Button>

IDataErrorInfo

This interface is used to synchronize errors in the view model on to the screen. When your ViewModel implements this interface, the screen will send it the name of each property that it is bound to, in order to tell if there is a validation error with it. If an error is returned the default red line around the control is displayed.

public interface IDataErroInfo
  {
    string this[string columnName];
    public string Error {get;}
  }

  public interface IValidation
  {
    bool IsValid { get; }
    string Message { get;  }
  }

  class Validation : IValidation
  {
    Func<bool> condition;

    public Validation(Func<bool> condition, string message)
    {
        condition = condition;
        Message = message;
    }

    public bool IsValid
    {
        get { return condition(); }
    }

    public string Message { get;set;}
  }

  public class ViewModel : IDataErrorInfo
  {
    public TodoItemViewModel(ITodoItemRepository todoItemRepository)
    {
      validations = new Dictionary<string, IValidation>
      {
        {"Description", new Validation(() => !string.IsNullOrEmpty(Description), "Cannot have an empty description.")},
        {"DueDate", new Validation(() => DueDate >= DateTime.Now, "Due Date must occur on or after today.")}
      };
    }

    public string Description { get;set; }
    public DateTime DueDate{ get; set; }

    public string this[string columnName]
    {
      get
      {
        var validation = validations[columnName];
        return validation.IsValid ? null : validation.Message;
      }
    }

    public string Error
    {
      get { return BuildErrors(); }
    }

    private string BuildErrors()
    {
      var builder = new StringBuilder();
      foreach (var validation in validations.Values)
        if(!validation.IsValid)
          builder.AppendLine(validation.Message);
      return builder.ToString();
    }

    private IDictionary<string, IValidation> validations;
  }

  <DockPanel>
    <DockPanel.Resources>
    <Style x:Key="ValidationStyle" TargetType="Control">
    <Style.Triggers>
      <Trigger Property="Validation.HasError" Value="true">
        <Setter Property="Control.ToolTip" Value="{Binding RelativeSource={x:Static RelativeSource.Self}, Path=(Validation.Errors)[0].ErrorContent}" />
        <Setter Property="Control.BorderBrush" Value="Red" />
        <Setter Property="Control.BorderThickness" Value="2" />
      </Trigger>
    </Style.Triggers>
    </Style>
    </DockPanel.Resources>
    <TextBox Width="200" Text="{Binding Path=Description, ValidatesOnDataErrors=True, UpdateSourceTrigger=PropertyChanged}" Style="{StaticResource ResourceKey=ValidationStyle}" />
    <DatePicker SelectedDate="{Binding Path=DueDate, ValidatesOnDataErrors=True, UpdateSourceTrigger=PropertyChanged}" Style="{StaticResource ResourceKey=ValidationStyle}" />
  </DockPanel>

Data Binding

DataContext

The class System.Windows.FrameworkElement has a property on it named DataContext of type object. This is a very special property that every screen widget inherits. When the DataContext is set to an object, every control within that control has its DataContext set to that same object.

In the following example, when the DataContext is set on the DockPanel, the Label and Button have the same DataContext. That means that the Label and the Button can bind to properties on the same object.

<Window x:Class="MainWindow">
    <DockPanel>
      <Label Text="{Binding Path=Name}"></Label>
      <Button Command={Binding Path=Save}></Button>
    </DockPanel>
  </Window>

  public partial class MainWindow : Window
  {
    public Window()
    {
      InitializeComponent();
      ViewModel = new ViewModel();
    }

    public ViewModel ViewModel
    {
      get { return (ViewModel) DataContext; }
      set { DataContext = value; }
    }
  }

  public class ViewModel
  {
    public string Name{get;set;}
    public ICommand Save{get;set;}
  }

IValueConverter

Value converters are used to convert objects from one type to another. When used in the UI, the value converter is used to convert back and forth from the View to the ViewModel.

public interface IValueConverter
  {
    object Convert(object value, Type targetType, object parameter, CultureInfo culture);
    object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture);
  }
    
  <Window.Resources>
    <BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
  </Window.Resources>

  <Image Source="..\Images\warning.png" Visibility="{Binding Path=IsDisabled, Mode=OneWay, Converter={StaticResource BooleanToVisibilityConverter}}" />
comments powered by Disqus