CommandBinding relative path - c#

Within my window (let's say MyCanvas) there's a new command definition which I then bind to my window. Usually the handlers for CanExecute and Executed are directly within MyCanvas. But is it somehow possible to bind the CanExecute and Executed handlers to a relative path like for example MyCanvas.Logic.CanExecute_OpenCamera?
This is my current XAML.
<Window.Resources>
<RoutedUICommand x:Key="OpenCamera" Text="Open camera" />
</Window.Resources>
<Window.CommandBindings>
<CommandBinding Command="{StaticResource OpenCamera}" CanExecute="CanExecute_OpenCamera" Executed="Executed_OpenCamera"/>
</Window.CommandBindings>
This is what I'm trying to define. Logic is public property of MyCanvas.
<Window.Resources>
<RoutedUICommand x:Key="OpenCamera" Text="Open camera" />
</Window.Resources>
<Window.CommandBindings>
<CommandBinding Command="{StaticResource OpenCamera}" CanExecute="Logic.CanExecute_OpenCamera" Executed="Logic.Executed_OpenCamera"/>
</Window.CommandBindings>

You can, but you have to use converters which create delegates to the respective methods from a bound object of the class, or from its type, if the methods are static. See http://wpfglue.wordpress.com/2012/05/07/commanding-binding-controls-to-methods/ for details.

Related

RoutedCommand in UserControl is not working as expected

I am trying to use RoutedCommands in my UserControls, following the example in this article:
https://joshsmithonwpf.wordpress.com/2008/03/18/understanding-routed-commands/
I defined the RoutedCommand and CommandBindings in the UserControl instead of in the article's example. I am trying to use it in my MainWindow, so that when the Button is clicked, the Command in the UserControl is executed. However, the Button is disabled and the Foo_CanExecute() method is never executed.
<UserControl x:Class="RoutedCommandTest.ViewControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:RoutedCommandTest"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<UserControl.CommandBindings>
<CommandBinding
Command="{x:Static local:ViewControl.Foo}"
PreviewCanExecute="Foo_CanExecute"
PreviewExecuted="Foo_Executed"
/>
</UserControl.CommandBindings>
<Grid>
</Grid>
</UserControl>
Here is the code for ViewControl.xaml.cs:
public static readonly RoutedCommand Foo = new RoutedCommand();
void Foo_CanExecute(object sender, CanExecuteRoutedEventArgs e)
{
e.CanExecute = true;
}
void Foo_Executed(object sender, ExecutedRoutedEventArgs e)
{
MessageBox.Show("The Window is Fooing...");
}
public ViewControl()
{
InitializeComponent();
}
And here is the code for MainWindow.xaml:
<Window x:Class="RoutedCommandTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:RoutedCommandTest"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<local:ViewControl/>
<Button Content="Foo" Margin="0 5" Command="{x:Static local:ViewControl.Foo}"/>
</Grid>
</Window>
I would like to know how to fix the issue so that the Button is enabled and the Foo_CanExecute() method is executed when the Button is clicked.
Your command is in a usercontrol, whilst the button is in mainwindow.
Which presumably contains your usercontrol.
Like bubbling and routing events ( which are used to drive them ).
Executed looks for the command bubbling UP the visual tree to the binding.
PreviewExecuted looks for the command tunnelling DOWN the visual tree to the binding.
Since your button is in the parent of the usercontrol I'm not sure whether either bubbling or tunnelling will work.
But tunnelling would be PreviewExecuted And PreviewCanExecute.
https://learn.microsoft.com/en-us/dotnet/api/system.windows.input.commandbinding.previewexecuted?view=netframework-4.8
https://learn.microsoft.com/en-us/dotnet/api/system.windows.input.commandbinding.previewcanexecute?view=netframework-4.8
Routedcommands can be pretty tricky to get right.
One thing you sometimes have to do is to bind commandtarget to tell it where to go look.
eg:
<Grid>
<local:UserControl1 x:Name="UC1" Height="60" Width="100"/>
<Button Content="Foo" TextElement.FontSize="30" Command="{x:Static local:UserControl1.Foo}"
CommandTarget="{Binding ElementName=UC1}"
/>
</Grid>
Works for me.
I have rarely found them useful - this is one of the aspects makes them way less useful than you might at first imagine.
EDIT:
It's perhaps worth mentioning the other thing makes these unattractive compared to a regular icommand. You need to either use a static which means it's only suitable for very generic commands OR you need event handlers which will be in code behind.
On the other hand.
If you're writing something has to work generically with whatever has focus. Like say a text editor with multiple textboxes and you're doing text manipulation. A routed command might be suitable. I have never encountered such a requirement in apps I've worked on though.

Keyboard shortcut for wpf menu item

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>

CommandConverter cannot convert from System.String in WPF

I have strange error in WPF using .NET Framework 4.5
<Window.CommandBindings>
<CommandBinding Command="ImportExcelCmd" CanExecute="ImportExcelCmd_CanExecute" Executed="ImportExcelCmd_Executed"></CommandBinding>
</Window.CommandBindings>
<Window.InputBindings>
<KeyBinding Key="I" Modifiers="Control" Command="ImportExcelCmd"></KeyBinding>
</Window.InputBindings>
I receive an error that CommandConverter cannot convert from System.String
Where is my mistake ?
I have another binding to a ListView, like:
<ListView.CommandBindings>
<CommandBinding Command="Delete" CanExecute="Delete_CanExecute" Executed="Delete_Executed"></CommandBinding>
</ListView.CommandBindings>
<ListView.InputBindings>
<KeyBinding Key="Delete" Command="Delete"></KeyBinding>
</ListView.InputBindings>
and it works.
If you want to use Custom Routed commands, you to use more verbose definition.
Declare the routed command as static in class and then use it in XAML using x:Static.
You can refer to the answer here.
For the sake of completeness of the answer, I am posting the relevant code from the answer here:
namespace MyApp.Commands
{
public class MyApplicationCommands
{
public static RoutedUICommand ImportExcelCmd
= new RoutedUICommand("Import excel command",
"ImportExcelCmd",
typeof(MyApplicationCommands));
}
}
XAML
<Window x:Class="..."
...
xmlns:commands="clr-namespace:MyApp.Commands">
...
<Window.CommandBindings>
<CommandBinding
Command="{x:Static commands:MyApplicationCommands.ImportExcelCmd}"
CanExecute="ImportExcelCmd_CanExecute"
Executed="ImportExcelCmd_Executed" />
</Window.CommandBindings>

how to add multiple command bindings in wpf

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"/>

Custom command not working

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));

Categories

Resources