In all examples that I checked, first two arguments of RoutedUICommand() are same string, e.g.
private static RoutedUICommand add = new RoutedUICommand("Add", "Add", typeof(CommandLibrary));
What the difference between them?
You can always check the metadata for the meaning by pressing F12 with your I-beam on the class while using Visual Studio.
Anyway, with the constructor RoutedUICommand(String, String, Type): the first string is a descriptive text, the second is the name, and the third is the owner type. It doesn't have to be the same.
Consider this example here:
public static RoutedCommand GreetUserCommand = new RoutedUICommand("Howdy! Just to say hello, nothing else.", "GreetUser", typeof(MainWindow));
and usage of the view:
<Window.CommandBindings>
<CommandBinding Command="{x:Static loc:MainWindow.GreetUserCommand}"
CanExecute="GreetUser_CanExecute" Executed="GreetUser_Executed"/>
</Window.CommandBindings>
<Window.ContextMenu>
<ContextMenu>
<MenuItem Command="{x:Static loc:MainWindow.GreetUserCommand}"/>
</ContextMenu>
</Window.ContextMenu>
Related
I checked a lot of of answers here about shortcuts bindings, but did not find the simple way to execute some method from the C# code.
First, in the following classic example I don't understand what actually we are binding. What the meaning of Command attribute? What is the ApplicationCommands? Where is ApplicationCommands.Open has been declared?
<Window.InputBindings>
<KeyBinding Command="ApplicationCommands.Open"
Gesture="CTRL+R" />
</Window.InputBindings>
In the one of answer of question similar to my one, "XAML is the markup language, so we could not call the method from there" has been told. OK, in this case, WHY we can call the method OnClickBtn1 from the code below?
<Button
x:Name="SomeButton"
Click="OnClickBtn1"/>
Finally, my problem. All I need is to execute OnClickBtn1 method by Ctrl+H (for example) shortcut same as effect when the button Btn1 clicked. I understand that following code is not enough.
XAML:
<Window x:Name="MainDisplay"
<!-- ... --->
>
<Window.InputBindings>
<KeyBinding Gesture="Ctrl+H" Command="{Binding OnClickBtn1}" />
</Window.InputBindings>
<!-- ... -->
<Button x:Name="Btn1"
Width="70"
Content="Button"
Click="OnClickBtn1"/>
C#:
public partial class MainWindow : Window {
public MainWindow() {
InitializeComponent();
}
private void OnClickBtn1(object sender, RoutedEventArgs e) {
System.Diagnostics.Debug.WriteLine("Btn1 has been clicked or Ctrl+H had been inputed");
}
}
I am trying to add a keyboard shortcut to the menu item in my xaml code using
<MenuItem x:Name="Options" Header="_Options" InputGestureText="Ctrl+O" Click="Options_Click"/>
with Ctrl+O
But it is not working - it is not calling the Click option.
Are there any solutions for this?
InputGestureText is just a text. It does not bind key to MenuItem.
This property does not associate the input gesture with the menu item; it simply adds text to the menu item. The application must handle the user's input to carry out the action
What you can do is create RoutedUICommand in your window with assigned input gesture
public partial class MainWindow : Window
{
public static readonly RoutedCommand OptionsCommand = new RoutedUICommand("Options", "OptionsCommand", typeof(MainWindow), new InputGestureCollection(new InputGesture[]
{
new KeyGesture(Key.O, ModifierKeys.Control)
}));
//...
}
and then in XAML bind that command to some method set that command against MenuItem. In this case both InputGestureText and Header will be pulled from RoutedUICommand so you don't need to set that against MenuItem
<Window.CommandBindings>
<CommandBinding Command="{x:Static local:MainWindow.OptionsCommand}" Executed="Options_Click"/>
</Window.CommandBindings>
<Menu>
<!-- -->
<MenuItem Command="{x:Static local:MainWindow.OptionsCommand}"/>
</Menu>
you should succeed in this way:
Defining MenuItem Shortcuts
By using KeyBindings:
<Window.CommandBindings> <CommandBinding Command="New" Executed="CommandBinding_Executed" /> </Window.CommandBindings> <Window.InputBindings> <KeyBinding Key="N" Modifiers="Control" Command="New"/> </Window.InputBindings>
When using ApplicationCommands class I get a lot of things for free. Text, shortcut and localisation. However there seems to be (or I haven't found it) a way to specify the Character you would specifiy by the _ notation (e.g. E_xit). Is there a way to specify that character for instance for the
ApplicationCommands.New ?
Or is the only solution to this using a
CustomRountedUICommand
where I can simply specify _New for the name property?
EDIT:
To clarify here an extraction of my xaml file:
<MenuItem Name="NewProject" Command="{Binding MenuNewProject}" />
MenuNewProject is an ApplicationCommand.New with an InputGesture added. But how to add the underscore without setting the menu header (which is already done by the command binding)?
Edit2:
As it has been pointed out this is obviously a Menu issue. Now the question is: Is there an alternative to the _ in the text to specify the accelerator key? I haven't found anything in the MenuItem class.
Final solution:
Either use:
AccessKeyManager.Register('N',MenuItem)
but loose the shown underlined N or set
MenuItem.Header ='_New'
manually and loose the localization. Unfortunately parsing ApplicationCommands.New.Name always gives back the English name. There might be a solution with the ContentPresenter class but that is a little bit overshot for my small project.
Use an underscore _ in the Header text to create a hotkey or use a InputBinding to create a shortcut (from this answer):
<Window.CommandBindings>
<CommandBinding Command="New" Executed="CommandBinding_Executed" />
</Window.CommandBindings>
<Window.InputBindings>
<KeyBinding Key="N" Modifiers="Control" Command="New"/>
</Window.InputBindings>
RoutedUICommand's do not specify an accelerator key or shortcut key because they may be placed in multiple locations, potentially with different parameters (making them in effect different commands). Thus, the onus for applying accelerators is on the Menu which hosts the commands. You'll need to assign these yourself.
<MenuItem Header="_New"
Command="ApplicationCommands.New" />
The shortcut key you specify using an InputBinding in the XAML or in Code Behind.
<Window.InputBindings>
<KeyBinding Key="N"
Modifiers="Control"
Command="ApplicationCommands.New" />
</Window.InputBindings>
The shortcut key should show up in your menu automatically.
I am working with WPF. I want to create keyboard shortcuts for my WPF application. I have created as following. The first command binding tag for "open" is working and command binding for exit is not working. I dont know what is the reason.
<Window.CommandBindings>
<CommandBinding Command="Open" Executed="CommandBinding_Executed"/>
<CommandBinding Command="Exit" Executed="CommandBinding_Executed_1" />
</Window.CommandBindings>
<Window.InputBindings>
<KeyBinding Command="Open" Key="O" Modifiers="control" />
<KeyBinding Command="Exit" Key="E" Modifiers="control"/>
</Window.InputBindings>
Above code is getting the following error:
Cannot convert string 'Exit' in attribute 'Command' to object of type
'System.Windows.Input.ICommand'. CommandConverter cannot convert from
System.String. Error at object 'System.Windows.Input.CommandBinding' in
markup file 'WpfApplication2;component/window1.xaml' Line 80 Position 25.
You problem is that there is no exit command. You'll have to roll your own.
See here for built-in ApplicationCommands
It's pretty easy to create your own, I use a static utility class to hold common commands that I use often. Something like this:
public static class AppCommands
{
private static RoutedUICommand exitCommand = new RoutedUICommand("Exit","Exit", typeof(AppCommands));
public static RoutedCommand ExitCommand
{
get { return exitCommand; }
}
static AppCommands()
{
CommandBinding exitBinding = new CommandBinding(exitCommand);
CommandManager.RegisterClassCommandBinding(typeof(AppCommands), exitBinding);
}
}
Then you should be able to bind it like this:
<KeyBinding Command="{x:Static local:AppCommands.Exit}" Key="E" Modifiers="control"/>
In my XAML I have this:
<UserControl.CommandBindings>
<CommandBinding Command="Help"
CanExecute="HelpCanExecute"
Executed="HelpExecuted" />
</UserControl.CommandBindings>
<MenuItem Header="Help" Command="Help" />
This works fine. So when I click the context menu, HelpExecuted() gets called.
Now I want to do the same again except use a custom command instead of the Help command. So what I do is:
public RoutedCommand MyCustomCommand = new RoutedCommand();
and change my XAML to:
<UserControl.CommandBindings>
<CommandBinding Command="MyCustomCommand"
CanExecute="HelpCanExecute"
Executed="HelpExecuted" />
</UserControl.CommandBindings>
<MenuItem Header="Help" Command="MyCustomCommand" />
But i get the error: Cannot convert string 'MyCustomCommand' in attribute 'Command' to object of type 'System.Windows.Input.ICommand'. CommandConverter cannot convert from System.String.
What am I missing here? And please note that I want to do it all in XAML, i.e. don't want to use CommandBindings.Add(new CommandBinding(MyCustomCommand....
Oops, sorry, was a bit fast to post my original answer. I now see that the problem is not with the type but with the CommandBinding. You need to use a markup extension to resolve the command name. I usually make my commands static in their declaration like this:
namespace MyApp.Commands
{
public class MyApplicationCommands
{
public static RoutedUICommand MyCustomCommand
= new RoutedUICommand("My custom command",
"MyCustomCommand",
typeof(MyApplicationCommands));
}
}
And in the XAML:
<UserControl x:Class="..."
...
xmlns:commands="clr-namespace:MyApp.Commands">
...
<UserControl.CommandBindings>
<CommandBinding Command="{x:Static commands:MyApplicationCommands.MyCustomCommand}"
CanExecute="HelpCanExecute"
Executed="HelpExecuted" />
</UserControl.CommandBindings>
You need to bring in the namespace of the containing class by using xmlns. I called it 'commands' in my example above.
Original post below:
Try changing the type of the command to RoutedUICommand. The constructor is a bit different:
public RoutedUICommand MyCustomCommand
= new RoutedUICommand("Description", "Name", typeof(ContainingClass));