Monday, August 26, 2013

What is TemplateBinding in WPF – short example.

TemplateBinding has to do with the ControlTemplate, in brief it is a way to inject property into the template from the template user. You've probably heard about the lookless nature of WPF controls which means that unlike behavior (which is fixed), the appearance of a control can be replaced entirely by supplying a new ControlTemplate.

Consider the following template for a ToggleButton. This is simply a polygon with a stroke and an orange fill.
<Window x:Class="TemplateBindingTest.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="350" Width="525">
<Grid>
<Grid.Resources>
  <Style x:Key="PolygonToggleButtonStyle" TargetType="ToggleButton">
    <Style.Setters>
      <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="ToggleButton">
            <Polygon Name="CenterPolygon" Points="90,10 50, 50, 10,10" 
            Fill="Orange" Stroke="Gray" StrokeThickness="0"/>
            <ControlTemplate.Triggers>
              <Trigger Property="IsChecked" Value="True">
                <Setter TargetName="CenterPolygon" Property="StrokeThickness" Value="3"/>
              </Trigger>
            </ControlTemplate.Triggers>
          </ControlTemplate>
        </Setter.Value>
      </Setter>
    </Style.Setters>
  </Style>
</Grid.Resources>

<StackPanel Width="100">
  <ToggleButton Background="Pink" Style="{StaticResource PolygonToggleButtonStyle}"/>
</StackPanel>
</Grid>
</Window>

See that in spite of setting the Background property to Pink, the button is still orange since this is the value hardcoded in template.


Because we provided our own ControlTemplate we must explicitly say how the template should use parameters provided by the control's user. This is a situation when TemplateBinding becomes handy. We will instruct the Fill property to capture the value of Background property in the following way.

<Polygon Name="CenterPolygon" Points="90,10 50, 50, 10,10" 
Fill="{TemplateBinding Background}" Stroke="Gray" StrokeThickness="0"/>

Wednesday, August 7, 2013

Another Observer Pattern implementation (with expressions and delegates)

This is an example of the Observer Pattern implementation in C# where the registration and announcing about events is handled by a separate class Observation. It has two public methods: one for registering for an action (used by subscribers) and one for informing about events (used by publishers). Expression is used to capture the method name the observer wants to register for and Action delegate is used to capture the method name that the subject wants to raise.

public interface ISubject<T>
{
  void RegisterFor(Expression<Action<T>> action, Action callback);
}

public interface IObservers
{
  void InformOf(Action action);
}
  
public class Observation<T> : IObservers, ISubject<T>
{
  private readonly Dictionary<string, Action> callbacks = new Dictionary<string, Action>();

  public void RegisterFor(Expression<Action<T>> action, Action callback)
  {
    var key = KeyFrom(action);
    if (callbacks.ContainsKey(key))
      callbacks[key] += callback;
    else
      callbacks[key] = callback;
  }

  public void InformOf(Action action)
  {
    var key = KeyFrom(action);
    if (callbacks.ContainsKey(key))
      callbacks[key]();
  }

  private string KeyFrom(Action action)
  {
    return action.Method.Name;
  }

  private string KeyFrom(Expression<Action<T>> action)
  {
    var methodExpressionSignature = (action.Body as MethodCallExpression).ToString();
    return ExtractMethodName(methodExpressionSignature);
  }

  private string ExtractMethodName(string signature)
  {
    return signature.Split(new[] { '.', '(' })[1];
  }
}

An interface is introduced to specify the actions being observed:

public interface IApplicationState
{
  void Starting();
  void Stopping();
}

public class Application : IApplicationState
{
  IObservers _observers;
  public Application(IObservers observers)
  {
    _observers = observers;
  }

  public void Starting()
  {
    /*...*/
    _observers.InformOf(Starting);
  }

  public void Stopping()
  {
    /*...*/
    _observers.InformOf(Stopping);
  }
}

An example of use:

static void Main(string[] args)
{
  var observation = new Observation<IApplicationState>();
  var app = new Application(observation);

  observation.RegisterFor(action: change => change.Starting(),
                          callback: () => Console.WriteLine("application is starting."));

  app.Starting();
  app.Stopping();

  Console.ReadLine();
}
//OUTPUT:
//application is starting.