Welcome to EMC Consulting Blogs Sign in | Join | Help

Darius Collins' Blog

Using Delegate Commands with WPF Views (UPDATED)

UPDATED: Scroll to end of post.

Please note:  the examples in this post depend on an implementation of the Presentation Model described in a previous post. 

DelegateCommand<T> is a class that comes with the Composite Application Library (CAL or PRISM), which is the latest incarnation of the Composite application block (CAB).  I have included it in my solution for an application that is based on CAB and have also created a second class DelegateCommand which extends DelegateCommand<T> simply by overriding the constructors and specifying T as object.  This second class allows you to use delegate commands when you don't need to use a command parameter.  I will not go into detail here regarding the implementation of the DelegateCommand<T> class (you can look at the code for yourself – see the attached zip file at the bottom of the post), but will stick to describing how it is used.

Delegate commands can be used instead of WPF Routed commands.  The advantage of a delegate command is that they can be bound to directly on the PresentationModel without the need for a pass through method in the View's code behind.  The command parameters are also type safe, whereas with Routed Commands, parameters are always of type object, and so need to be cast before use.

 Delegate commands are exposed on the Presentation Model as a property.  For example:

OrdersPresentationModel: AddCommand Property

public DelegateCommand<Order> AddCommand { get; set; }

Here we are declaring a DelegateCommand<T>. If the command is to be passed a command parameter, the type of the parameter should be included as the template for the command.  If not, use DelegateCommand instead (no template).

I have chosen to use automatic properties for my commands.  I therefore need to initialise the commands from the OnViewReady method.  (Alternatively, I could have included the initialisation in the getter via a null check). I do this by calling the InitialiseCommands method:

OrdersPresentationModel: InitialiseCommands Method

private void InitialiseCommands()

{

    ...

    AddCommand = new DelegateCommand<Order>(OnAdd, CanAdd);

    ...

}

 My OnAdd() and CanAdd() methods are also declared in the presentation model as follows:

OrdersPresentationModel: OnAdd and CanAdd Methods

private static bool CanAdd(Order order)

{

    return order != null;

}

private void OnAdd(Order order)

{

    if (order == null) return;

    Customer.Orders.AddUnique(Order);

}

So how do we use the command?  As simple as any other property binding:  

OrdersView

<Button Margin="5,0,5,0"

        Height="20"

        Width="70"

        Command="{Binding AddCommand}"

        CommandParameter="{Binding ElementName=ordersComboBox, Path=SelectedItem}">

 

 That's it.  Very simple.  Notice that the OnAdd and CanAdd methods are private.  How can we test them then?  Better than just testing the methods, we can actually call the command from the test.  

OrdersPresentationModelTest

public void AddCommand_AddOrder_OrderAddedToCustomersOrdersCollection()

{

    ....

   _model.AddCommand.Execute(new Order(1));

    ....

    model.AddCommand.CanExecute(new Order(1));

    ....

} 

UPDATE:  Thanks to a tip off from a colleague of mine at EMC, Marcin Kaluza, regarding Josh Smith’s excellent post Allowing CommandManager to query your ICommand objects, I have updated the DelegateCommand class by removing the RaiseCanExecuteChanged and the OnCanExecuteChanged methods and instead implementing add and remove accessors on the CanExecuteChanged event that hook the event up to the CommandManager.RequerySuggested event.  As a result, we no longer need to implement a DispatcherTimer (as suggested below) for each view to periodically poll the CanExecute methods.  I’m sure you’ll agree, this is a much neater solution and has the added bonus of removing the concern of CPU spiking, since we are no longer polling the can execute methods every half second or so, but only when the CommandManager detects conditions that might change the ability of a command to execute.  Thanks Josh!

 There is just one fly in the ointment with this approach.  The CanExecute fires only once when the view is loaded.  This seems like a flaw in the DelegateCommand, since the WPF's Routed Command regularly polls CanExecute methods.  There may now be other implementations of the delegate command that claim to have solved this problem (the Relay Command may be one of them), but I have yet to research them.  In the mean time I have implemented a DispatcherTimer that raises the RaiseCanExecuteChanged() on the delegate command every half second.  This is initialised from the OnViewReady method by calling the InitialiseCanExecuteDispatcherTimer()  method on the PresentationModel.  Ideally this should be pushed down into the DelegateCommand class, but I have yet to look into solving that particular problem.

OrdersPresentationModel: InitialiseCanExecuteDispatcherTimer Method

private void InitialiseCanExecuteDispatcherTimer()

{

    _dispatcherTimer = new DispatcherTimer { Interval = new TimeSpan(0, 0, 0, 0,500) };
    _dispatcherTimer.Tick += (sender, e) => AddCommand.RaiseCanExecuteChanged();
    _dispatcherTimer.Start();

} 

Published Monday, November 23, 2009 4:20 PM by darius.collins

Attachment(s): DelegateCommand.zip

Comment Notification

If you would like to receive an email when updates are made to this post, please register here

Subscribe to this post's comments using RSS

Comments

 

darius.collins said:

This post has been updated - if you have used this post to implement delegate commands, it is vital that you read the update - it will save you a fair bit of effort, since you no longer need to implement a dispatcher timer to poll Can Execute methods!

November 26, 2009 2:55 PM
 

user1 said:

thank you!!

April 21, 2011 6:54 PM

Leave a Comment

(required) 
(optional)
(required) 
Submit
Powered by Community Server (Personal Edition), by Telligent Systems