How do I add a custom routed command in WPF?
Asked Answered
K

3

51

I have an application that contains Menu and sub menus. I have attached Appliocation Commands to some of the sub menu items such as Cut, Copy and Paste.
I also have some other menu items that do not have application commands.
How could I add a custom command binding to those sub menu items?
I have gone through this article but unable to attach event to my sub menu items.

Kenyettakenyon answered 2/3, 2009 at 5:52 Comment(1)
Found this youtube link. youtube.com/watch?v=mG4l0AaYBTMCruickshank
O
100

I use a static class that I place after the Window1 class (or whatever the window class happens to be named) where I create instances of the RoutedUICommand class:

public static class Command {

    public static readonly RoutedUICommand DoSomething = new RoutedUICommand("Do something", "DoSomething", typeof(Window1));
    public static readonly RoutedUICommand SomeOtherAction = new RoutedUICommand("Some other action", "SomeOtherAction", typeof(Window1));
    public static readonly RoutedUICommand MoreDeeds = new RoutedUICommand("More deeds", "MoreDeeeds", typeof(Window1));

}

Add a namespace in the window markup, using the namespace that the Window1 class is in:

xmlns:w="clr-namespace:NameSpaceOfTheApplication"

Now I can create bindings for the commands just as for the application commands:

<Window.CommandBindings>
    <CommandBinding Command="ApplicationCommands.Open" Executed="CommandBinding_Open" />
    <CommandBinding Command="ApplicationCommands.Paste" Executed="CommandBinding_Paste" />
    <CommandBinding Command="w:Command.DoSomething" Executed="CommandBinding_DoSomething" />
    <CommandBinding Command="w:Command.SomeOtherAction" Executed="CommandBinding_SomeOtherAction" />
    <CommandBinding Command="w:Command.MoreDeeds" Executed="CommandBinding_MoreDeeds" />
</Window.CommandBindings>

And use the bindings in a menu for example:

<MenuItem Name="Menu_DoSomething" Header="Do Something" Command="w:Command.DoSomething" />
Orsola answered 2/3, 2009 at 6:10 Comment(7)
Having the static class to hold the RoutedUICommands was the key for me. (If they were in my Window1 class, the XAML couldn't find them.) Thanks!Spalato
The importance of the class being static really cannot be understated. Frustratingly, WPF seems to silently ignore commands if they are defined in a non-static class.Cashman
Why the downvote? If you don't explain what it is that you think is wrong, it can't improve the answer.Orsola
FYI - don't make the same rookie mistake I did: the static properties (e.g. Command.DoSomething) have to be public, otherwise you will receive the following exception "CommandConverter cannot convert from System.String". I'm assuming this is because the code that is managing commands is probably in a different assembly, and as a result can't see the internal property. I just started learning WPF last week :DLightless
I Googled quite a bit until I found this nice and concise explanation how to do things. Thank you!Ochre
@Orsola In your Static Command class did you mean typeof(Command) instead of typeof(Window1)Untuck
@nam: No, the owner of the routed command is the window, not my little utility class.Orsola
J
73

Instead of defining them in a static class, you might as well declare the commands directly in XAML. Example (adapted from Guffas nice example):

<Window.Resources>
    <RoutedUICommand x:Key="DoSomethingCommand" Text="Do Something" />
    <RoutedUICommand x:Key="DoSomethingElseCommand" Text="Do Something Else" />
</Window.Resources>
<Window.CommandBindings>
    <CommandBinding Command="{StaticResource DoSomethingCommand}" Executed="CommandBinding_DoSomething" />
    <CommandBinding Command="{StaticResource DoSomethingElseCommand}" Executed="CommandBinding_DoSomethingElse" />
</Window.CommandBindings>
...
<MenuItem Name="Menu_DoSomething" Header="Do Something" Command="{StaticResource DoSomethingCommand}" />
Jeffers answered 15/6, 2010 at 15:38 Comment(5)
Does any of this bind to actual C# code? If so, how? What purpose do the RoutedUICommands serve? What functionality do they add?Affined
@EdJ.Plunkett: 1. Yes. 2. Through the CommandBindings: CommandBinding_DoSomething and CommandBinding_DoSomethingElse are C# code. 3./4. For a general discussion about the advantages of RoutedCommands vs. regular Button_Click-bindings, see, for example, joshsmithonwpf.wordpress.com/2008/03/18/… (Section "Who Cares?").Jeffers
Thanks. I was wondering what the RoutedUICommands add relative to Guffa's example, not relative to regular to old-fashioned onclick handling (if I understand you -- which if I necessarily did, I wouldn't be asking all this!), but I'll look for that in the Josh Smith article.Affined
@EdJ.Plunkett: Ah, ok. Guffa also uses RoutedUICommands, he just declares them in a static class instead of in the XAML. That's the only difference between his example and mine. It's a matter of preference of where you want to have them.Jeffers
I like this answer best. Much cleaner.Heathenish
B
20

I Know that my answer is too late, but i hope it will help for the future.

I Like Guffa and Heinzi answers, but you can use only one command to achieve the previous result. I usually use the Help command

 <Window.CommandBindings>
        <CommandBinding Command="{StaticResource Help}" Executed="HelpExecuted" />
  </Window.CommandBindings>

and I use CommandParametr with each call e.g

<Window.InputBindings>
    <KeyBinding Command="{StaticResource Help}" Key="A" Modifiers="Ctrl" CommandParameter="Case1"/>
    <KeyBinding Command="{StaticResource Help}" Key="B" Modifiers="Ctrl" CommandParameter="Case2"/>
    <KeyBinding Command="{StaticResource Help}" Key="C" Modifiers="Ctrl" CommandParameter="Case3"/>
    <KeyBinding Command="{StaticResource Help}" Key="D" Modifiers="Ctrl" CommandParameter="Case4"/>
    <MouseBinding Command="{StaticResource Help}" MouseAction="LeftDoubleClick" CommandParameter="Case5" />
</Window.InputBindings>

or

<Button Command="Help" CommandParameter="Case6" Content="Button">
    <Button.InputBindings>
        <KeyBinding Command="{StaticResource Help}" Gesture="Ctrl+D" CommandParameter="Case7"/>
    </Button.InputBindings>
</Button>

and in the cs file

private void HelpExecuted(object sender, ExecutedRoutedEventArgs e)
{
    string str = e.Parameter as string;
    switch (str)
    {
        case null://F1 Pressed default Help
               //Code
            break;
        case "Case1":
               //Code
            break;
        case "Case2":
               //Code
            break;
        case "Case3":
               //Code
            break;
        case "Case4":
            break;
        case "Case5":
               //Code
            break;
        case "Case6":
               //Code
            break;
        case "Case7":
               //Code
            break;
    }
    e.Handled = true;
}

and if you are using MVVM pattern

private void HelpExecuted(object sender, ExecutedRoutedEventArgs e)
{
    string str = e.Parameter as string;
    Mvvm_Variable.Action(Input: str);
    e.Handled = true;
}

and move the switch to ViewModule site. and Action is a method in the same ViewModule class.

Barrack answered 31/8, 2011 at 10:4 Comment(5)
Just the ticket! Using the Properties value of a Command has opened up so many new possibilities for me :-) I just used ApplicationCommands.NotACommand with Properties for MinimizeWindow, MaximizeWindow and RestoreDownWindowColly
I like this (anything to reduce boiler plate!), but it's worth noting that it does have a limitation - text that would be included in, for example, menu entries is defined per command, so if you need (or may later add) menus, this method may not be the best (I often bind button labels to the command text too).Detriment
@Bob, It is a simple switch statement, the limitation is per form you'll use all shortcut combination which will reflect the command parameter string. in this case even routed command will not help you.Barrack
Sorry @Waleed, I'm not following you. Perhaps I wasn't clear, though. Both Guffa and Heinzi use RoutedUICommand in their answers. This class has a Text property, from which text is taken to automatically populate menu entries which invoke that command (and can be used elsewhere - I bind button text to it quite often through a shared template). If you use one command (say, "Help"), all the menu items will have the same single piece of text defined in Help.Text. Depending on your preferred architecture, this may not be a big problem, but I think it's something to be aware of.Detriment
Sorry @Bob I miss understand you, thanks for explainingBarrack

© 2022 - 2024 — McMap. All rights reserved.