'WPF change bound command for keybindings based on property?
I have a xaml window that I want to bind the Escape key
to different commands in my view model depending on the value of a boolean property.
IsSearching == true
, bind to a CancelSearch command
IsSearching == false
, bind to a Close command.
Is there a way to do this without a code behind?
Solution 1:[1]
<Window>
<Window.InputBindings>
<KeyBinding Command="{Binding SomeCommand}" Key="F5"/>
</Window.InputBindings>
</Window>
This is a workaround
private ICommand someCommand;
public ICommand SomeCommand
{
get
{
return someCommand
?? (someCommand = new ActionCommand(() =>
{
if(IsSearching)
OnCancelExecute();
else
OnCloseExecute();
}));
}
}
Solution 2:[2]
You can't do everything directly in XAML, and sometimes, some code-behind is needed.
Here's how I'd do it if I didn't want to spend hours searching for a pure XAML solution.
In your XAML, give a x:Name
to your Keybinding (here, searchKey
).
Then in code-behind, add something like this in your constructor:
public partial class YourView
{
public YourView()
{
InitializeComponent();
var vm = DataContext as YourViewModel;
vm.PropertyChanged += (s, e) =>
{
if (e.PropertyName != "IsSearching")
return;
searchKey.Command = vm.IsSearching ? vm.SearchCommand : vm.CancelCommand:
};
}
}
Solution 3:[3]
Another way to hande this is to implement custom KeyBinding
class and keep your ViewModel or code behind as clean as possible.
MultiKeyBinding.cs
using Prism.Commands;
using System.Windows;
using System.Windows.Input;
namespace ExampleDemoApp
{
/// <summary>
/// An extended <see cref="KeyBinding"/> that covers binding to two commands and switch between them (<see cref="UseSecondaryCommand"/>).
/// </summary>
public class MultiKeyBinding : KeyBinding
{
public MultiKeyBinding()
{
this.Command = new DelegateCommand<object?>(this.OnExecuteCommand);
}
private void OnExecuteCommand(object? parameter)
{
var command = this.UseSecondaryCommand ? this.SecondaryCommand : this.PrimaryCommand;
var commandParameter = this.UseSecondaryCommand ? this.SecondaryCommandParameter : this.PrimaryCommandParameter;
if (command.CanExecute(commandParameter))
command.Execute(commandParameter);
}
public bool UseSecondaryCommand
{
get => (bool)GetValue(UseSecondaryCommandProperty);
set => SetValue(UseSecondaryCommandProperty, value);
}
public static readonly DependencyProperty UseSecondaryCommandProperty = DependencyProperty.Register(
nameof(UseSecondaryCommand), typeof(bool), typeof(MultiKeyBinding), new PropertyMetadata(defaultValue: false));
public ICommand PrimaryCommand
{
get => (ICommand)GetValue(PrimaryCommandProperty);
set => SetValue(PrimaryCommandProperty, value);
}
public static readonly DependencyProperty PrimaryCommandProperty = DependencyProperty.Register(
nameof(PrimaryCommand), typeof(ICommand), typeof(MultiKeyBinding), new PropertyMetadata(null));
public object PrimaryCommandParameter
{
get => (object)GetValue(PrimaryCommandParameterProperty);
set => SetValue(PrimaryCommandParameterProperty, value);
}
public static readonly DependencyProperty PrimaryCommandParameterProperty = DependencyProperty.Register(
nameof(PrimaryCommandParameter), typeof(object), typeof(MultiKeyBinding), new PropertyMetadata(null));
public ICommand SecondaryCommand
{
get => (ICommand)GetValue(SecondaryCommandProperty);
set => SetValue(SecondaryCommandProperty, value);
}
public static readonly DependencyProperty SecondaryCommandProperty = DependencyProperty.Register(
nameof(SecondaryCommand), typeof(ICommand), typeof(MultiKeyBinding), new PropertyMetadata(null));
public object SecondaryCommandParameter
{
get => (object)GetValue(SecondaryCommandParameterProperty);
set => SetValue(SecondaryCommandParameterProperty, value);
}
public static readonly DependencyProperty SecondaryCommandParameterProperty = DependencyProperty.Register(
nameof(SecondaryCommandParameter), typeof(object), typeof(MultiKeyBinding), new PropertyMetadata(null));
}
}
Usage:
<UserControl.InputBindings>
<local:MultiKeyBinding
Key="Esc"
PrimaryCommand="{Binding CloseCommand}"
SecondaryCommand="{Binding CancelSearchCommand}"
UseSecondaryCommand="{Binding IsSearching, UpdateSourceTrigger=PropertyChanged, Mode=OneWay}"
/>
</UserControl.InputBindings>
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | |
Solution 2 | |
Solution 3 | yurislav |