web-dev-qa-db-ja.com

RelayCommandのキーバインド

アプリで RelayCommand を使用しています。ビューモデルにコードを配置するのに最適ですが、キーストロークをコマンドにバインドするにはどうすればよいですか?

RoutedUICommandにはInputGesturesプロパティがあり、キーストロークを押すとコマンドが自動的に呼び出されます。 (追加のボーナスとして、MenuItemにキーストロークを表示することもできます。)残念ながら、RoutedUICommandの追加プロパティ用の再利用可能なインターフェイスがないため、同じ魔法を取得するRelayUICommandを作成することはできません。

私はすでにInputBindingsを使用してみました:

<Window.InputBindings>
    <KeyBinding Key="PageUp" Command="{Binding SelectPreviousLayerCommand}"/>
</Window.InputBindings>

ただし、KeyBinding.Commandは依存関係プロパティではないため、実行時例外が発生します。 (実際、KeyBindingはDependencyObjectでもないというのが不満です。)そして、RelayCommandはViewModelのプロパティであるため(RoutedUICommandが設計されている静的フィールドとは対照的に)、データバインディングは私が知っている唯一の方法です。 XAMLから参照します。

どうやってこれを解決しましたか?キーストロークをRelayCommandにバインドする最良の方法は何ですか?

27
Joe White

KeyBindingクラスのCommandプロパティは、データバインディングをサポートしていません。この問題は.NET4.0で解決される予定であり、今後の.NET 4.0 Beta2バージョンで確認できるはずです。

14
jbe

あなたが説明している理由から、XAMLからこれを行うことはできないと思います。

私はコードビハインドでそれを行うことになりました。それはコードですが、それは1行のコードであり、それでもかなり宣言的であるため、私はそれと一緒に暮らすことができます。ただし、これがWPFの次のバージョンで解決されることを心から望んでいます。

これが私のプロジェクトの1つからのコードのサンプル行です:

this.InputBindings.Add(new KeyBinding(
    ((MedicContext)this.DataContext).SynchronizeCommand,
    new KeyGesture(Key.F9)));

この場合のSynchronizeCommandはRelayCommandのインスタンスであり、(明らかに)F9がそれをトリガーします。

17
Mark Seemann

KeyBindingをサブクラス化し、Commandプロパティを設定するCommandBinding依存関係プロパティを追加してから、他の入力バインディングと同様にXAMLに追加できます。

public class RelayKeyBinding : KeyBinding
{
    public static readonly DependencyProperty CommandBindingProperty =
        DependencyProperty.Register("CommandBinding", typeof(ICommand), 
        typeof(RelayKeyBinding),
        new FrameworkPropertyMetadata(OnCommandBindingChanged));
    public ICommand CommandBinding
    {
        get { return (ICommand)GetValue(CommandBindingProperty); }
        set { SetValue(CommandBindingProperty, value); }
    }

    private static void OnCommandBindingChanged(
        DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var keyBinding = (RelayKeyBinding)d;
        keyBinding.Command = (ICommand)e.NewValue;
    }
}

XAML:

<Window.InputBindings>
    <RelayKeyBinding 
        Key="PageUp" 
        CommandBinding="{Binding SelectPreviousLayerCommand}" />
</Window.InputBindings>
10

CommandReferenceクラスを使用できます。

非常にエレガントなコードで、魅力のように機能します。

以下をご覧ください: コンポジットWPFでキー押下をDelegateCommandに関連付けるにはどうすればよいですか?

これはRelayCommandsでも同じように機能しますが、CommandReferenceは呼び出しCommandManager.RequerySuggestedを使用しないため、CanExecutesは更新されません。自動CanExecute再評価を実現するために必要なのは、内部で次の変更を行うことだけです。 CommandReferenceクラス

public event EventHandler CanExecuteChanged
{
     add { CommandManager.RequerySuggested += value; }
     remove { CommandManager.RequerySuggested -= value; }
}
2
GuYsH

コマンドとキーをリンクするキーバインディングをビューモデルに作成します。

        this.KeyBinding = new KeyBinding();
        //set the properties
        this.KeyBinding.Command = this.Command;
        this.KeyBinding.Key = this.Key;
        //modifier keys may or may not be set
        this.KeyBinding.Modifiers = this.ModifierKeys;

次に、ビューモデルルートにInputBindingアイテムのコレクションを作成し、それらをウィンドウのコードビハインドのInputBindingsに追加します。

     foreach (var item in applicationViewModel.InputBindingCollection) {
        this.InputBindings.Add(item);
     }

私が知っている背後のコードで何かをするのは悪い形ですが、バインディングを行う方法はまだわかりませんが、まだ取り組んでいます。 :)このdoentが私に与える唯一のものは、メニューのキーコマンド修飾子リストですが、それは来ることです。

0
Aran Mulholland