The problem

In WPF you expect your components/controls to behave exactly as you want to.... but this not always the case.
For example : why does this combobox not execute a command when I change the selection or more often why this textbox does not execute a command when I press the Enter (return) key ?

This problem often occurs when you use the - well know - pattern M-V-VM and it's sometimes hard to find a workaround. Today I will explain you a design pattern, know as the Ramora pattern which I find very useful.
By the way, you can also use it to create a library of behaviors for all your projects...

Wanted application

Ramora pattern

One solution (or the ramora pattern explained)


The idea

The solution is based on the attached properties (MSDN page here) of the WPF binding engine. With this mechanism you can attach any property to any object you want and it's massively used in layout controls (DockPanel.Dock for example)..

By attaching and detaching properties we will attach some handlers on the events of our choice to add behaviors to the controls. The value passed by the property will also be useful as a data storage....


The steps are :

  1. Create a class of your choice, no inheritance needed,
  2. Declare an attachedProperty by registering it and adding the corresponding GetXXX and SetXXX,
  3. Add an event handler to the change of this property : inside it, add an event handler to the event you want to catch (for example MouseEnter),
  4. Add the behavior logic inside this last event handler
  5. Attach this behaviors to the aimed control inside your XAML (after you'd declared the XMLNS)


An example

In this example we'll try to add a nice beahavior to any IInputElement : anytime the user presses the 'Enter' key, it will execute a Command.

We'll then declare a Command attached property of type 'ICommand' which will be the command to execute on a given event (very original isnt it ?).

#region Command Property
/// <summary>
/// Enables Command functionality
/// </summary>
public static ICommand GetCommand(DependencyObject obj)
{
	return (ICommand)obj.GetValue(CommandProperty);
}
 
/// <summary>
/// Enables Command functionality
/// </summary>
public static void SetCommand(DependencyObject obj, ICommand value)
{
	obj.SetValue(CommandProperty, value);
}
 
/// <summary>
/// Enables Command functionality
/// </summary>
public static readonly DependencyProperty CommandProperty =
	DependencyProperty.RegisterAttached("Command",
 typeof(ICommand),
 typeof(CommandOnEnter), 
new UIPropertyMetadata(null, new PropertyChangedCallback(CommandPropertyChanged)));



Then everytimes the property is assigned we will attach or detach our event handlers on the DependencyObject which uses it. In our case this is an IInputElement.

/// <summary>
/// Command property changed callback
/// </summary>        
static void CommandPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
	//Test in debug mode if it's binded to the correct type of element...
	Debug.Assert(sender is IInputElement, "Attached property only for a IInputElement");
	if (sender is IInputElement)
	{
		IInputElement inputElement = sender as IInputElement;
 
		// Clean when Command is released
		if (e.OldValue != null)
		{
			Detach(inputElement);
		}
 
		//Attach the behavior
		if (e.NewValue != null)
		{
			Attach(inputElement);
		}
 
	}
}
 
/// <summary>
/// Clean event handlers
/// </summary>
/// <param name="inputElement">The aimed IInputElement</param>
private static void Detach(IInputElement inputElement)
{
	inputElement.PreviewKeyDown -= CommandOnEnter_PreviewKeyDown;
	if (inputElement is FrameworkElement)
		(inputElement as FrameworkElement).Unloaded -= CommandOnEnter_Unloaded;
}
 
 
private static void Attach(IInputElement inputElement)
{
	inputElement.PreviewKeyDown += new KeyEventHandler(CommandOnEnter_PreviewKeyDown);
	if (inputElement is FrameworkElement)
		(inputElement as FrameworkElement).Unloaded += new RoutedEventHandler(CommandOnEnter_Unloaded);
 
}



The keyPressed event handler checks if the enter key is pressed and execute the command if yes. The command to execute is retrieved via the attachedProperties system of WPF (GetValue method) :

static void CommandOnEnter_PreviewKeyDown(object sender, System.Windows.Input.KeyEventArgs e)
{
	if (sender is IInputElement)
	{
		var textBox = sender as IInputElement;
		if (e.Key == Key.Enter && e.KeyboardDevice.Modifiers == ModifierKeys.None)
		{
			ICommand cmd = GetCommand(sender as DependencyObject) as ICommand;
			cmd.Execute(null);
		}
 
	}
}



That's all !

Adding a parameter ?

What if you want to pass a parameter to the executed Command ? You will simply have to add another Attached property and get it's value in the keyPressed event handler.

/// <summary>
/// Enables CommandParameter functionality
/// </summary>
public static object GetCommandParameter(DependencyObject obj)
{
	return (object)obj.GetValue(CommandParameterProperty);
}
 
/// <summary>
/// Enables CommandParameter functionality
/// </summary>
public static void SetCommandParameter(DependencyObject obj, object value)
{
	obj.SetValue(CommandParameterProperty, value);
}
 
/// <summary>
/// Enables CommandParameterProperty functionality
/// </summary>
public static readonly DependencyProperty CommandParameterProperty =
	DependencyProperty.RegisterAttached("CommandParameterProperty", typeof(object), typeof(CommandOnEnter));

Funny things to do

The ramora pattern can be used to do a lot of things, here is a list of some I'am thinking :

  • Execute a command on a textbox when pressing enter,
  • Select all the text when a textbox gets the focus,
  • Etc...



Here are some links you may find useful :

  1. Thinking in WPF: attached properties
  2. More advanced attached property use: the Ramora pattern
  3. Behaviors in Silverlight 4.0



Shout it kick it on DotNetKicks.com