简体   繁体   English

C#/WPF:KeyBinding 不触发命令

[英]C#/WPF: KeyBinding not triggering Command

I have declared <InputBindings>我已经声明了<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-V 时没有任何反应。 Ctrl-C seems to work. Ctrl-C 似乎有效。 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?任何人都知道为什么我的PasteImageCommand没有触发?

I am using .NET 4 btw我正在使用 .NET 4 顺便说一句

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 ?我发现我需要将KeyBindings放在 MainWindow 中,但命令在ViewModel ,我如何在ShellView设置键绑定,然后绑定到ShellViewModel命令?

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. 您设置用户控件的DataContext,但请确保命令可以绑定到它。 Sometimes, WPF just uses the order of appearance, and the DataContext is set later then the commands. 有时,WPF只使用外观顺序,然后在命令之后设置DataContext。

Probably, the output window of VS already shows binding errors for the commands. 可能VS的输出窗口已经显示命令的绑定错误。 Try putting the DataContext definition on top (and teach yourself to do this for all views). 尝试将DataContext定义放在最前面(并教导自己为所有视图执行此操作)。

To avoid hardcoded KeyBindings, I have derived Josh Smiths RelayCommand-Class and added Shortcut-related stuff: 为了避免硬编码的KeyBindings,我派生了Josh Smiths RelayCommand-Class并添加了与Shortcut相关的东西:

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: 然后在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) 通过这种方法,我可以允许用户在运行时调整快捷方式(在我的配置窗口中)

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. 我有类似的情况,其中Key相关事件仅在Shell View中被收听,并且没有调到按下该键的实际视图。 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. 为了克服这个问题,我编写了一个小的附加行为来将焦点设置为用户控件或框架元素以接收对初始加载的关注,并且通过我想要监听的UI元素来监听关键笔划。

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 -VJ

In this case you can provide keybindings in your RoutedCommand declaration: 在这种情况下,您可以在RoutedCommand声明中提供键绑定:

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

This should work. 这应该工作。

Try this: 试试这个:

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

Are you using 3.5 or 4? 你使用的是3.5还是4?

In 3.5 its "feature". 在3.5其“功能”。 UserControl.InputBindings is not part of dataContext tree so you cannot bind to items of class, that is bound to parent. UserControl.InputBindings不是dataContext树的一部分,因此您无法绑定绑定到父级的类的项。 eg. 例如。 DataBinding wont work and you need to set DataBinding or whole KeyBinding in code by hand. DataBinding不起作用,您需要手动在代码中设置DataBinding或整个KeyBinding。

Its fixed in 4. 它固定在4。

this is too old post put I will add the answer, maybe someone need it 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 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由于焦点问题,用户控件中的输入绑定应使用后面的用户控件代码分配给主窗口

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM