Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I have multiple CommandBindings for the same Command on the same control?

I have a UserControl that adds a CommandBinding to it's CommandBindings collection to handle a specific Command. Later I use this control in a window and want to add another binding to that same control to add additional behavior. The problem though, is that when I do this it seems that when I add another CommandBinding to the CommandBindings collection of a control that it replaces any binding that was already made for the same Command. So what it seems like is that a control can only have a single CommandBinding per control, is this correct?

Please see the code example below which attempts to set two CommandBindings for the same Save Command.

<Window x:Class="MultipleCommandBindings.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="Save"
                    Executed="CommandBinding_Executed" />
    <CommandBinding Command="Save"
                    Executed="CommandBinding_Executed" />
</Window.CommandBindings>
<Grid>
    <Button Height="23"
            HorizontalAlignment="Right"
            Margin="0,0,25,88"
            Name="button1"
            VerticalAlignment="Bottom"
            Width="75"
            Command="Save">Button</Button>
</Grid>

Originally I was expecting either a compile-time or runtime exception when wrote this code but was surprised that it didn't complain. Next though I was disappointed since my CommandBinding_Executed handler only gets called once instead of twice as I was hoping.

Update: After a bit of testing it appears that my second CommandBinding is not overwriting my first one but instead it appears that even though I'm not setting Handled to true in my event handler that the first command binding swallows up the Command. I'm pretty sure at this point that the solution to my problem is to understand why the routed command is not propagating past the first handler even when Handled is not set to true.

Update: I've found this great little tidbit of information which just confirms some of the strange behavior behind Command routing in WPF.

Update: One thought about how to work around the fact that it appears that there can only be a single effective CommandBinding per command is that it appears that the default CommandBinding class exposes Executed and CanExecute as events which of course like all events can have multiple handlers. The idea then is to have some other way than the standard CommandBindings.Add method to add additional handlers to a command. Maybe this could be done via an extension method on the Control class and conjunction with a custom CompositeCommandBinding class which allows us to aggregate multiple bindings within one main binding.

like image 683
jpierson Avatar asked Feb 18 '10 16:02

jpierson


People also ask

What is command binding?

CommandBinding. A CommandBinding associates a command with the event handlers that implement the command. The CommandBinding class contains a Command property, and PreviewExecuted, Executed, PreviewCanExecute, and CanExecute events. Command is the command that the CommandBinding is being associated with.

How to use command binding in WPF?

Bind the command in the HierarchyNavigator control. To do this, create a new instance of the ViewModel sample class and set DataContext for the parent StackPanel. This will reflect changes in the children. Whenever the selected item changes, the TextBox Text value will change.


1 Answers

So far I've only been able to come up with a workaround for this problem which is to handle the command at two different levels in the logical tree. In the example below I handle the Save command within my grid and then also again within the Window element.

<Window x:Class="MultipleCommandBindings.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="Save"
                    Executed="CommandBinding_Executed2"/>
</Window.CommandBindings>
<Grid>
    <Grid.CommandBindings>
        <CommandBinding Command="Save"
                        Executed="CommandBinding_Executed1" />
    </Grid.CommandBindings>

    <Button Height="23"
            HorizontalAlignment="Right"
            Margin="0,0,25,88"
            Name="button1"
            VerticalAlignment="Bottom"
            Width="75"
            Command="Save">Button</Button>
</Grid>

In order to get this to work my code behind needs to also manually propagate the Command execution to the next level up.

    private void CommandBinding_Executed1(object sender, ExecutedRoutedEventArgs e)
    {
        System.Diagnostics.Debug.WriteLine("Executed 1!");
        var command = e.Command as RoutedUICommand;
        command.Execute(e.Parameter, this);
    }

    private void CommandBinding_Executed2(object sender, ExecutedRoutedEventArgs e)
    {
        System.Diagnostics.Debug.WriteLine("Executed 2!");
    }

If anybody has any better ideas on how I can monitor a command still let it propagate naturally up the tree I would love to see it otherwise I might just resort to this workaround.

like image 120
jpierson Avatar answered Oct 18 '22 08:10

jpierson