Creating custom commands for the Composite Application library(Prism v2) 

Tags:

The Composite Application Library helps architects and developers create composite Windows Presentation Foundation (WPF) and Silverlight applications. Composite applications are composed of discrete, functionally complete, pieces that work together to create a single, integrated user interface. The Composite Application Library accelerates the development of composite applications using proven design patterns to help you build these types of applications.

Commands are a way to handle user interface (UI) actions. They are a loosely coupled way to bind the UI to the logic that performs the action.

When building composite applications, presentation design patterns such as Model-View-Presenter (MVP) and Model-View-Controller (MVC) are often used to separate the UI logic from the UI layout and presentation. When implementing these patterns with Windows Presentation Foundation (WPF), the presenter or controller handles commands but lives outside the logical tree. WPF-routed commands deliver command messages through UI elements in the tree, but the elements outside the tree will not receive these messages because they only propagate events up or down from the focused element or an explicitly stated target element. Additionally, the WPF-routed commands require a command handler in the code behind.

The Composite Application Library introduces two new commands that can be routed outside the boundaries of the logical tree and that do not require handling logic in the code behind. The commands are custom implementations of the ICommand interface defined by WPF, and they implement their own routing mechanism to get the command messages delivered to objects outside of the logical tree. The commands in the Composite Application Library include DelegateCommand and CompositeCommand.

The command support in WPF is at this moment rather limited. Very few of the default controls support binding to a command. One of the controls that has a Command dependency property is the Button.


If we want to execute some code on button press and we want to leverage the commanding support, we need a few things in the view model and in the XAML view:

1. a property for the command

public ICommand ClickCommand {get; set;} 

2. Initialization code for the command (eventually in the view model’s constructor)

public MyConstructor()
{
ClickCommand = new DelegateCommand<object>(OnClickCommand);
}

3. Command handler:

private void OnClickCommand(object argument)
{ /**/ }

4. and some XAML code in the view that guarantees the command will be executed on button click:

<Button Height="24" x:Name="MyButton"  
Command=”{Binding ClickCommand}”/>

This is straightforward if you are familiar with the M-V-VM pattern.

Let’s consider another scenario where we need to execute a command for the lost focus event of a TextBox. To be able to solve this in the same manner as above we would need to use the Command dependency property of the TextBox and bind a DelegateCommand to it.

Unfortunately, the TextBox does not accept commands by default for the lost focus event.

A solution to the problem is to use the attached properties feature of WPF.

The goal is to create an attached property for the TextBox. The attached property’s name will also be Command and the command bound to it will handle the PreviewLostKeyboardFocus event. After we have this, we will be able to write the following code in the XAML view:

<UserControl xmlns:Commands= "clr-namespace:{namespace containing the attached command class}">
<TextBox Commands:PreviewLostKeyboardFocus.Command="{Binding MyTextBoxPreviewLostKeyboardFocus}"/>
</UserControl>

The code in the view model is identical as for the Button scenario (but with suggestive variable and method names of course):

public ICommand LostFocusCommand {get; set;}
public MyConstructor()
{
ClickCommand = new DelegateCommand<object>(OnLostFocusCommand);
}
private void OnLostFocusCommand(object argument)
{ … }

Now let’s dive into the implementation of the attached CommandProperty.
public class PreviewLostKeyboardFocus
{
/*Dependency property for the Command attached property.
For the Command property to be bindable it has to be dependency property.*/
public static readonly DependencyProperty CommandProperty = DependencyProperty.RegisterAttached(
"Command",
typeof (ICommand),
typeof (PreviewLostKeyboardFocus),
new PropertyMetadata(OnSetCommandCallback));

public static readonly DependencyProperty LostFocusCommandBehaviorProperty =
DependencyProperty.RegisterAttached("LostFocusCommandBehavior",
typeof (TextBoxLostFocusCommandBehavior),
typeof (PreviewLostKeyboardFocus),
null);

/*Acessor methods for the Command attached property*/
public static void SetCommand(TextBox textBox, ICommand command)
{
textBox.SetValue(CommandProperty, command);
}

public static ICommand GetCommand(TextBox textBox)
{
return textBox.GetValue(CommandProperty) as ICommand;
}

/*Callback executed when the Command property is databound*/
private static void OnSetCommandCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var textBox = d as TextBox;
if (textBox != null)
{
TextBoxLostFocusCommandBehavior behavior = GetOrCreateBehavior(textBox, e.NewValue as ICommand);
}
}

/*Creates the command behavior if it does not already exist*/
private static TextBoxLostFocusCommandBehavior GetOrCreateBehavior(TextBox textBox, ICommand command)
{
var behavior = textBox.GetValue(LostFocusCommandBehaviorProperty) as TextBoxLostFocusCommandBehavior;
if (behavior == null)
{
behavior = new TextBoxLostFocusCommandBehavior(textBox, command);
textBox.SetValue(LostFocusCommandBehaviorProperty, behavior);
}
return behavior;
}

#region Nested type: TextBoxLostFocusCommandBehavior

/*Wrapper for the PreviewLostKeyboardFocus event*/
public class TextBoxLostFocusCommandBehavior : CommandBehaviorBase<TextBox>
{
public TextBoxLostFocusCommandBehavior(TextBox textBox, ICommand command) : base(textBox)
{
Command = command;
textBox.PreviewLostKeyboardFocus += (sender, args) => Command.Execute(new PreviewLostKeyboardFocusCommandArgs
{
Sender = (TextBox) sender,
KeyboardFocusChangedEventArgs = args
});
}
}

#endregion
}

As it’s obvious from the event wrapper class, the event forwards the sender and the event arguments to the command. So the command’s handler has access to the same data as the event itself. the PreviewLostKeyboardFocusCommandArgs  class is a custom class used to transfer parameters:

public class PreviewLostKeyboardFocusCommandArgs
{
public TextBox Sender { get; set; }
public KeyboardFocusChangedEventArgs KeyboardFocusChangedEventArgs { get; set; }}

The PreviewLostKeyboardFocus class might seem quite verbose, but this is the standard WPF way of defining attached properties that can take part in the data binding binding process.

Most of the code is standard and can be extracted in a R# template. The template can be downloaded here.

That’s it!

With just a little coding effort we can have a clean view and be able to wrap WPF event in Commands and handle the view events in the view model or controller(depending of the design approach).

 
Posted by Voicu Matei on 25-Sep-09
2 Comments  |  Trackback Url | Bookmark this post with:        
 
ab

Comments


Kindler Chase commented on Tuesday, 19-Jan-2010
Thanks for the R# template... certainly makes short work out of creating Prism Commands!!!


Kindler Chase commented on Tuesday, 19-Jan-2010
There is a missing method call for GetCommandParameter in the R# template that needs to be added: public static object GetCommandParameter($ControlType$ $ControlName$) { return $ControlName$.GetValue(CommandParameterProperty); }

Your name  *
Email  *
Your URL 
Comment  *

Please enter the text from the image


Contact us - Raas Van Gaverestraat 83, 9000 Gent, Belgium - Tel. +32 (9) 330.15.00 - Privacy Statement - Sitemap - Sign In Developed with Microsoft Office SharePoint Server 2007