11

I have declared <InputBindings>

<UserControl.InputBindings>
    <KeyBinding Key="C" Modifiers="Ctrl" Command="{Binding CopyImageCommand}" />
    <KeyBinding Key="V" Modifiers="Ctrl" Command="{Binding PasteImageCommand}" />
</UserControl.InputBindings>

For testing purposes, I have added buttons bound to those commands too

<Button Command="{Binding CopyImageCommand}" Content="Copy" />
<Button Command="{Binding PasteImageCommand}" Content="Paste" />

I noticed that when the paste button is enabled, when i press Ctrl-V nothing happens. Ctrl-C seems to work. For that, a list box item is selected, I am not sure if it makes any difference. Anyone knows why is my PasteImageCommand not triggering?

I am using .NET 4 btw

UPDATE

A fuller code snipplet

<UserControl x:Class="QuickImageUpload.Views.ShellView"
             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:vm="clr-namespace:QuickImageUpload.ViewModels"
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">
    <UserControl.InputBindings>
        <KeyBinding Key="C" Modifiers="Ctrl" Command="{Binding CopyImageCommand}" />
        <KeyBinding Key="V" Modifiers="Ctrl" Command="{Binding PasteImageCommand}" />
    </UserControl.InputBindings>
    <UserControl.DataContext>
        <vm:ShellViewModel />
    </UserControl.DataContext>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="50" />
            <RowDefinition Height="*" />

UPDATE

I found out I need to put the KeyBindings in the MainWindow, but the commands are in the ViewModel, how can i set key bindings in the ShellView which then binds to commands in the ShellViewModel?

4
  • Can you please post where are InputBinding specified? Its possible you put it in wrong place. Commented Oct 15, 2010 at 11:00
  • @Euphoric, I have put my InputBindings in the UserControl ShellView. I discovered it works when I put them in the MainWindow, but i need to set the view model to ShellViewModel, not really correct I think, how can I handle this? Commented Oct 19, 2010 at 2:44
  • 1
    @JiewMeng: Hi jiew! i have almost same problem. did you found any solution? Commented Mar 26, 2012 at 21:22
  • @Jalax, I havent been doing C# for some time, I'm afraid I cant remember if I solved this :( Commented Mar 28, 2012 at 11:52

7 Answers 7

7

Make sure that you are not having binding errors. You set the DataContext of the user control, but make sure that the commands can bind to it. Sometimes, WPF just uses the order of appearance, and the DataContext is set later then the commands.

Probably, the output window of VS already shows binding errors for the commands. Try putting the DataContext definition on top (and teach yourself to do this for all views).

Sign up to request clarification or add additional context in comments.

2 Comments

moving the input bindings to to bottom of the user control worked for me
I had multiple bindings going on and this post helped me realise to just go through each tag and defined the exact datacontext for each component. Thanks!
3

To avoid hardcoded KeyBindings, I have derived Josh Smiths RelayCommand-Class and added Shortcut-related stuff:

class UIRelayCommand : RelayCommand, INotifyPropertyChanged
{
    private static Dictionary<ModifierKeys, string> modifierText = new Dictionary<ModifierKeys, string>()
    {
        {ModifierKeys.None,""},
        {ModifierKeys.Control,"Ctrl+"},
        {ModifierKeys.Control|ModifierKeys.Shift,"Ctrl+Shift+"},
        {ModifierKeys.Control|ModifierKeys.Alt,"Ctrl+Alt+"},
        {ModifierKeys.Control|ModifierKeys.Shift|ModifierKeys.Alt,"Ctrl+Shift+Alt+"},
        {ModifierKeys.Windows,"Win+"}
    };

    private Key _key;
    public Key Key
    {
        get { return _key; }
        set { _key = value; RaisePropertyChanged("Key"); RaisePropertyChanged("GestureText"); }
    }

    private ModifierKeys _modifiers;
    public ModifierKeys Modifiers
    {
        get { return _modifiers; }
        set { _modifiers = value; RaisePropertyChanged("Modifiers"); RaisePropertyChanged("GestureText");}
    }

    public string GestureText
    {
        get { return modifierText[_modifiers] + _key.ToString(); }
    }

    public UIRelayCommand(Action<object> execute, Predicate<object> canExecute, Key key, ModifierKeys modifiers)
        : base(execute, canExecute)
    {
        _key = key;
        _modifiers = modifiers;
    }


    public event PropertyChangedEventHandler PropertyChanged;

    public void RaisePropertyChanged(string name)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(name));
    }
}

then create the command in the ViewModel:

private ICommand _newFileCommand;
public ICommand NewFileCommand
{
    get
    {
        if (_newFileCommand == null)
            _newFileCommand = new UIRelayCommand(p => OnNewFile(p), p => CanNewFile(p), Key.N, ModifierKeys.Control);
        return _newFileCommand;
    }
}
protected void OnNewFile(object p)
{
    //open file...
}
protected bool CanNewFile(object p)
{
    return true;
}

and bind it in the View:

<Window.InputBindings>
    <KeyBinding Command="{Binding NewFileCommand}" Key="{Binding NewFileCommand.Key}" Modifiers="{Binding NewFileCommand.Modifiers}"  />
</Window.InputBindings>
...
<MenuItem Header="New File" Command="{Binding NewFileCommand}" InputGestureText="{Binding NewFileCommand.GestureText}" />

With this approach I can allow the user to adjust the shortcuts at runtime (in my configuration-window)

1 Comment

+1...Excellent solution! One minor typo in the last code snippet: Modifiers="{Binding NewFileCommand.Modifier}" should be Modifiers="{Binding NewFileCommand.Modifiers}".
1

answer can be found in this link

https://social.msdn.microsoft.com/Forums/vstudio/en-US/395046c8-2cc8-48b4-9642-341ce0c99cc9/key-binding-does-not-work-always-in-mvvm-application?forum=wpf

due to focus issues, inputbindings in the usercontrol should be asigned to the mainwindow using usercontrol code behind

public partial class UserControl1 : UserControl
{
    public UserControl1()
    {
        InitializeComponent();
        this.DataContext = new ViewModel();
        this.Loaded += UserControl1_Loaded;
    }

    void UserControl1_Loaded(object sender, RoutedEventArgs e)
    {
        Window window = Window.GetWindow(this);
        foreach (InputBinding ib in this.InputBindings)
        {
            window.InputBindings.Add(ib);
        }
    }
}

Comments

0

Are you using 3.5 or 4?

In 3.5 its "feature". UserControl.InputBindings is not part of dataContext tree so you cannot bind to items of class, that is bound to parent. eg. DataBinding wont work and you need to set DataBinding or whole KeyBinding in code by hand.

Its fixed in 4.

1 Comment

I updated my the post with a fuller code snipplet showing where the input bindings are declared
0

I had a similar situation where in the Key related events were getting listened to only at the Shell View and was not tunelling to the actual view where the key was pressed. To overcome this problem, I wrote a small attached behavior to set the focus to the user control or the framework element to recieve the focus on initial load and that way the key strokes are listened to by the UI element I want to listen to.

public class FocusBehavior
{
    public static readonly DependencyProperty IsFocusedProperty = 
        DependencyProperty.RegisterAttached("IsFocused", typeof(bool?),typeof(FocusBehavior),
        new UIPropertyMetadata(false, new PropertyChangedCallback(OnFocusChanged)));
    public static bool? GetIsFocused(DependencyObject obj)
    {
        return (bool?)obj.GetValue(IsFocusedProperty);
    }
    public static void SetIsFocused(DependencyObject obj, bool? value)
    {
        obj.SetValue(IsFocusedProperty, value);
    }
    private static void OnFocusChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
    {
        var frameworkElement = sender as FrameworkElement;
        if (frameworkElement == null) return;
        if (args.OldValue == null) return;
        if (args.NewValue == null) return;
        if ((bool)args.NewValue)
        {
            frameworkElement.Loaded += OnFrameworkElementLoaded;
        }
    }

    private static void OnFrameworkElementLoaded(object sender, RoutedEventArgs args)
    {
        var frameworkElement = sender as FrameworkElement;
        frameworkElement.Focus();
        frameworkElement.Loaded -= OnFrameworkElementLoaded;
        var textControl = frameworkElement as JHATextEditor;
        if (textControl == null) return;
        textControl.SelectAll();
    }
}

And used it like this in one of my list views as below -

<GridViewColumn Width="Auto" Header="Value">
                    <GridViewColumn.CellTemplate>
                        <DataTemplate>
                            <Grid HorizontalAlignment="Stretch" MinWidth="100">
                                <TextBlock Text="{Binding FieldValue}" />
                            </Grid>
                            <DataTemplate.Triggers>
                                <DataTrigger Binding="{Binding IsSelected}" Value="True">
                                    <Setter Property="local:FocusBehavior.IsFocused" TargetName="FieldValueEditor" Value="True" />
                                </DataTrigger>
                            </DataTemplate.Triggers>
                        </DataTemplate>
                    </GridViewColumn.CellTemplate>
                </GridViewColumn>

Hope this helps.

-VJ

Comments

0

In this case you can provide keybindings in your RoutedCommand declaration:

public static RoutedCommand PasteImageCommand = new RoutedCommand("PasteImageCommand", typeof(YourType), new InputGestureCollection { new KeyGesture(Key.V, ModifierKeys.Control)});

This should work.

Comments

0

Try this:

<UserControl.InputBindings>
        <KeyBinding Key="C" Modifiers="Control" Command="{Binding CopyImageCommand}" />
        <KeyBinding Key="V" Modifiers="Control" Command="{Binding PasteImageCommand}" />
    </UserControl.InputBindings>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.