5
votes

From what I understand, the goal of the Command pattern is to help separate UI interaction from application logic. With properly implemented commands, a click on a "Print" menu item might result in a chain of interaction like this:

(button) ---click executes command----> (command) ---calls Print() in app logic ---> (logic)

This encourages you to separate the UI from the application logic.

I've been looking at WPF commands, and for the most part I see how they've implemented this pattern. However, I feel like to a certain extent they've complicated the Command pattern and managed to implement it in such a way that you are discouraged from separating the UI from application logic.

For example, consider this simple WPF window that has a button to paste text into the text box:

<Window x:Class="WpfApplication1.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="300" Width="300">
    <Window.CommandBindings>
        <CommandBinding Command="ApplicationCommands.Paste"
                        Executed="CommandBinding_Executed"/>
    </Window.CommandBindings>
    <StackPanel>
        <TextBox x:Name="txtData" />
        <Button Command="Paste" Content="Paste" />
    </StackPanel>
</Window>

Here's the code-behind:

namespace WpfApplication1
{
    public partial class Window1 : Window
    {
        public Window1()
        {
            InitializeComponent();
        }

        private void CommandBinding_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            ApplicationCommands.Paste.Execute(null, txtData);
        }
    }
} 

What did I gain from the command? It seems to me that I could have just as easily put the code from the command binding event handler into the button's Click event. Sure, now I can associate multiple UI elements with the Paste command and I only have to use the one event handler, but what if I want to paste to several different text boxes? I'd have to make the event handler logic more complicated or write more event handlers. So now, I feel like I have this:

(button) ---executes Routed Command---> (Window) ---executes command binding----(command binding)
(logic) <---calls application logic--- (event handler) <-----raises event --------------|

What am I missing here? It looks like an extra layer of indirection to me.

4

4 Answers

3
votes

You may be confusing concepts.

The ICommand interface supports the command pattern. That allows you to abstract user actions into a re-usable class.

Routed commands are a particular implementation of ICommand that search through the visual tree for handlers. They are particularly useful for commands that can be implemented by many different controls, and you want the current control to handle it. Think copy/paste. There could be a whole bunch of controls that might handle it, but by using the routed command, the routed command system will automatically find the correct control to handle the command based on focus.

2
votes

In addition to the things already mentioned, what you've forgotten in your specific Paste example are the CommandTarget and CommandParameter properties. For Paste, you can specify a TextBox by setting as the CommandTarget.

These properties are absolutely essential when want to use the same RoutedCommand from different controls. They allow you to give the Executed handler some information about the context in which the command is being invoked.

2
votes

I would favour using the RoutedCommands and RoutedUICommands when building controls. For example TextBox implements the UndoCommand for you and the Input guseture is already bound to Ctrl+Z. When building View Models, however, my preference is for a custom ICommand with internal implementations of Execute and CanExecute. The DelegateCommand provides this in Prism. This allows the view/xaml designer to only worry about the command and not the correct Execute/CanExecute handlers to use. This would allow for a more expressive view model.

ps. Delegate Commands dont yet work (elegantly) with InputBindings. Can some one at Microsoft fix this please!

0
votes

They can be overkill for some things, but you do get some nice benefits like CanExecute which can automagically enable/disable buttons/menu items when the command is not available (such as no text selected etc). You can also do command stuff in Blend, without using any code, which is great for designers.