11 votes

C#/WPF : KeyBinding ne déclenche pas la commande

J'ai déclaré

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

J'ai remarqué que lorsque le bouton coller est activé, lorsque j'appuie sur Ctrl-V, rien ne se passe. Ctrl-C semble fonctionner. Pour cela, un élément de la liste box est sélectionné, je ne sais pas si cela fait une différence. Quelqu'un sait pourquoi ma PasteImageCommand ne se déclenche pas?

J'utilise .NET 4 au fait

UPDATE

Un extrait de code plus complet

UPDATE

J'ai découvert que je dois mettre les 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 lient ensuite aux commandes dans le ShellViewModel?

6voto

Geert van Horrik Points 1809

Assurez-vous de ne pas avoir d'erreurs de liaison. Vous avez défini le DataContext du contrôle utilisateur, mais assurez-vous que les commandes peuvent y être liées. Parfois, WPF utilise simplement l'ordre d'apparition, et le DataContext est défini après les commandes.

Probablement, la fenêtre de sortie de VS montre déjà des erreurs de liaison pour les commandes. Essayez de mettre la définition du DataContext en haut (et habituez-vous à le faire pour toutes les vues).

3voto

0xDEADBEEF Points 1455

Pour éviter les KeyBindings codés en dur, j'ai dérivé de la classe RelayCommand de Josh Smith et ajouté des fonctionnalités liées aux raccourcis :

class UIRelayCommand : RelayCommand, INotifyPropertyChanged
{
    private static Dictionary modifierText = new Dictionary()
    {
        {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 execute, Predicate 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 liez-le dans la vue :

...

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

1voto

Hazem Elamir Points 41

La réponse peut être trouvée dans ce lien

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

En raison de problèmes de focus, les InputBindings dans le usercontrol doivent être assignées à la mainwindow en utilisant le code-behind du usercontrol

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

0voto

Euphoric Points 7641

Utilisez-vous la version 3.5 ou 4 ?

Dans la version 3.5, c'est une "fonctionnalité". UserControl.InputBindings ne fait pas partie de l'arborescence de dataContext, vous ne pouvez donc pas lier à des éléments de classe qui sont liés au parent. Par exemple, le DataBinding ne fonctionnera pas et vous aurez besoin de définir le DataBinding ou tout le KeyBinding manuellement dans le code.

C'est corrigé dans la version 4.

0voto

VBK Points 23

J'ai eu une situation similaire où les événements liés à la clé n'étaient écoutés qu'à la vue Shell et ne se propageaient pas à la vue réelle où la touche était pressée. Pour surmonter ce problème, j'ai écrit un petit comportement attaché pour définir le focus sur le contrôle utilisateur ou l'élément du framework pour recevoir le focus lors du chargement initial et de cette manière, les frappes de clavier 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 je l'ai utilisé comme ceci dans l'une de mes listes comme ci-dessous -

J'espère que cela aidera.

-VJ

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X