C # / WPF: KeyBinding не запускает команду - PullRequest
10 голосов
/ 15 октября 2010

Я объявил <InputBindings>

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

В целях тестирования я также добавил кнопки, связанные с этими командами

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

Я заметил, что когда кнопка вставки включена,когда я нажимаю Ctrl-V, ничего не происходит.Ctrl-C, кажется, работает.Для этого выбран элемент списка, я не уверен, если это имеет какое-либо значение.Кто-нибудь знает, почему мой PasteImageCommand не срабатывает?

Я использую .NET 4 btw

ОБНОВЛЕНИЕ

Полный фрагмент кода

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

ОБНОВЛЕНИЕ

Я обнаружил, что мне нужно поместить KeyBindings в MainWindow, но команды находятся в ViewModel, как я могу установить привязки клавиш в ShellViewкоторый затем связывается с командами в ShellViewModel?

Ответы [ 6 ]

6 голосов
/ 27 января 2011

Убедитесь, что у вас нет ошибок привязки. Вы устанавливаете DataContext пользовательского элемента управления, но убедитесь, что команды могут связываться с ним. Иногда WPF просто использует порядок появления, и DataContext устанавливается позже, чем команды.

Возможно, окно вывода VS уже показывает ошибки привязки для команд. Попробуйте поместить определение DataContext поверх (и научитесь делать это для всех представлений).

3 голосов
/ 31 августа 2012

Чтобы избежать жестко заданных привязок клавиш, я получил Josh Smiths RelayCommand-Class и добавил материал, связанный с ярлыками:

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

затем создайте команду в 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;
}

и связать его в представлении:

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

При таком подходе я могу позволить пользователю настроить ярлыки во время выполнения (в моем окне конфигурации)

0 голосов
/ 22 января 2014

Попробуйте это:

<UserControl.InputBindings>
        <KeyBinding Key="C" Modifiers="Control" Command="{Binding CopyImageCommand}" />
        <KeyBinding Key="V" Modifiers="Control" Command="{Binding PasteImageCommand}" />
    </UserControl.InputBindings>
0 голосов
/ 17 июля 2012

В этом случае вы можете указать привязку клавиш в объявлении RoutedCommand:

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

Это должно работать.

0 голосов
/ 01 июня 2012

У меня была похожая ситуация, когда в Key связанные события прослушивались только в Shell View и не настраивались на фактическое представление, где была нажата клавиша.Чтобы преодолеть эту проблему, я написал небольшое прикрепленное поведение для установки фокуса на пользовательский элемент управления или элемент фреймворка, чтобы получить фокус на начальную загрузку и таким образом, чтобы нажатия клавиш прослушивались элементом пользовательского интерфейса, который я хочу слушать.

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

И использовал это в одном из моих списков, как показано ниже -

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

Надеюсь, это поможет.

-VJ

0 голосов
/ 15 октября 2010

Используете ли вы 3,5 или 4?

В 3.5 его "фича". UserControl.InputBindings не является частью дерева dataContext, поэтому вы не можете привязать к элементам класса, который связан с родительским. например. DataBinding не будет работать, и вам нужно вручную установить DataBinding или весь KeyBinding в коде.

Исправлено в 4.

...