2010-10-15 18 views
9

J'ai déclaré <InputBindings>C#/WPF: KeyBinding ne peut pas déclencher de commande

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

Pour des fins de test, j'ai boutons ajouté liés à ces commandes trop

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

J'ai remarqué que lorsque le bouton de pâte est activé, quand j'appuie sur Ctrl-V rien ne se passe. Ctrl-C semble fonctionner. Pour cela, un élément de zone de liste est sélectionné, je ne suis pas sûr si cela fait une différence. Quelqu'un sait pourquoi mon PasteImageCommand ne se déclenche pas?

J'utilise .NET 4 BTW

MISE À JOUR

Un code plus complet 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="*" /> 

MISE À JOUR

J'ai découvert que je dois mettre la KeyBindings dans la MainWindow, mais les commandes sont dans le ViewModel, comment puis-je définir des liaisons de touches dans le ShellView qui se lie ensuite aux commandes dans le ShellViewModel?

+0

Pouvez-vous s'il vous plaît poster où sont spécifiés InputBinding? Il est possible que vous le mettiez au mauvais endroit. – Euphoric

+0

@Euphoric, j'ai mis mes InputBindings dans le UserControl ShellView. J'ai découvert que cela fonctionnait quand je les ai mis dans MainWindow, mais j'ai besoin de définir le modèle de vue à ShellViewModel, pas vraiment correct je pense, comment puis-je gérer cela? –

+1

@JiewMeng: Salut jiew! J'ai presque le même problème. Avez-vous trouvé une solution? – Jalal

Répondre

0

Utilisez-vous 3,5 ou 4?

Dans 3.5 sa "caractéristique". UserControl.InputBindings ne fait pas partie de l'arbre dataContext, donc vous ne pouvez pas lier les éléments de la classe, qui sont liés au parent. par exemple. DataBinding ne fonctionne pas et vous devez définir DataBinding ou KeyBinding entier dans le code à la main.

Son fixe dans 4.

+0

J'utilise .NET 4 –

+0

J'ai mis à jour mon post avec un snipplet de code plus complet montrant où les liens d'entrée sont –

3

Assurez-vous que vous n'êtes pas d'avoir des erreurs de liaison. Vous définissez le DataContext du contrôle utilisateur, mais assurez-vous que les commandes peuvent lier à lui. Parfois, WPF utilise simplement l'ordre d'apparition et le DataContext est défini plus tard que les commandes.

Probablement, la fenêtre de sortie de VS affiche déjà des erreurs de liaison pour les commandes. Essayez de placer la définition DataContext au-dessus (et apprenez-vous à le faire pour toutes les vues).

0

J'ai eu une situation similaire où dans les événements liés à la clé étaient écoutés seulement à la vue Shell et n'était pas en accord avec la vue réelle où la touche a été enfoncée. Pour résoudre ce problème, j'ai écrit un petit comportement attaché pour mettre l'accent sur le contrôle utilisateur ou l'élément de structure pour recevoir l'attention sur la charge initiale et ainsi les touches sont écoutées par l'élément d'interface utilisateur que je veux écouter.

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

et l'a utilisé comme celui-ci dans un de mes vues sur la liste ci-dessous -

<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

0

Dans ce cas, vous pouvez fournir des raccourcis clavier dans votre déclaration de RoutedCommand:

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

Cela devrait fonctionner.

4

Pour éviter KeyBindings hardcoded, je dérivé Josh Smith RelayCommand-Class et a ajouté des trucs liés Raccourci-:

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

puis créez la commande dans le 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; 
} 

et le lier dans la vue :

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

Avec cette approche, je peux permettre à l'utilisateur d'ajuster les raccourcis à l'exécution (dans ma configuration fenêtre)

+1

+1 ... Excellente solution! Une faute de frappe mineure dans le dernier extrait de code: Modifiers = "{Binding NewFileCommand.Modifier}" doit être Modifiers = "{Binding NewFileCommand.Modifiers}". –

0

Essayez ceci:

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