回答:
1つの方法は、ショートカットキーをコマンド自体にとして追加することInputGestures
です。コマンドはとして実装されRoutedCommands
ます。
これにより、ショートカットキーがコントロールに接続されていなくても機能します。また、メニュー項目はキーボードジェスチャーを理解するため、メニュー項目にコマンドをフックすると、メニュー項目のテキストにショートカットキーが自動的に表示されます。
コマンドを保持する静的属性を作成します(できれば、コマンド用に作成した静的クラスのプロパティとして、単純な例として、window.csで静的属性を使用するだけです)。
public static RoutedCommand MyCommand = new RoutedCommand();
メソッドを呼び出すショートカットキーを追加します。
MyCommand.InputGestures.Add(new KeyGesture(Key.S, ModifierKeys.Control));
実行時に呼び出すメソッドを指すコマンドバインディングを作成します。これらを動作させる必要のあるUI要素(ウィンドウなど)とメソッドのコマンドバインディングにこれらを配置します。
<Window.CommandBindings>
<CommandBinding Command="{x:Static local:MyWindow.MyCommand}" Executed="MyCommandExecuted"/>
</Window.CommandBindings>
private void MyCommandExecuted(object sender, ExecutedRoutedEventArgs e) { ... }
Executed
、コマンドのコードは、通常のコマンド(カスタムICommand
実装)を使用するのではなく、ビューモデルではなく(ウィンドウまたはユーザーコントロールの)コードビハインドになります。
これは、WPFのキーバインディングに関連して、まさに私が探していたものであることがわかりました。
<Window.InputBindings>
<KeyBinding Modifiers="Control"
Key="N"
Command="{Binding CreateCustomerCommand}" />
</Window.InputBindings>
ブログ投稿のMVVM CommandReferenceとKeyBindingを参照してください
このコードを試してください...
最初にRoutedComandオブジェクトを作成します
RoutedCommand newCmd = new RoutedCommand();
newCmd.InputGestures.Add(new KeyGesture(Key.N, ModifierKeys.Control));
CommandBindings.Add(new CommandBinding(newCmd, btnNew_Click));
どこで使いたいかによります。
TextBoxBase
から派生したコントロールはすでにこれらのショートカットを実装しています。カスタムのキーボードショートカットを使用する場合は、コマンドと入力ジェスチャーをご覧ください。以下は、Switch on the Codeの小さなチュートリアルです。WPFチュートリアル-コマンドバインディングとカスタムコマンド
他の人のためにこの答えを文書化します。これはめったに参照されず、XAMLを操作する必要がないため、これを行うはるかに簡単な方法があります。
キーボードショートカットをリンクするには、Windowコンストラクターで、新しいKeyBindingをInputBindingsコレクションに追加するだけです。コマンドとして、ICommandを実装する任意のコマンドクラスを渡します。executeメソッドの場合、必要なロジックを実装するだけです。以下の私の例では、WindowCommandクラスは、呼び出されるたびに実行されるデリゲートを取ります。バインディングで渡す新しいWindowCommandを作成するときは、初期化子でWindowCommandに実行させたいメソッドを指定するだけです。
このパターンを使用して、独自のクイックキーボードショートカットを作成できます。
public YourWindow() //inside any WPF Window constructor
{
...
//add this one statement to bind a new keyboard command shortcut
InputBindings.Add(new KeyBinding( //add a new key-binding, and pass in your command object instance which contains the Execute method which WPF will execute
new WindowCommand(this)
{
ExecuteDelegate = TogglePause //REPLACE TogglePause with your method delegate
}, new KeyGesture(Key.P, ModifierKeys.Control)));
...
}
実行デリゲートを受け取り、それに設定されたメソッドを起動する単純なWindowCommandクラスを作成します。
public class WindowCommand : ICommand
{
private MainWindow _window;
//Set this delegate when you initialize a new object. This is the method the command will execute. You can also change this delegate type if you need to.
public Action ExecuteDelegate { get; set; }
//You don't have to add a parameter that takes a constructor. I've just added one in case I need access to the window directly.
public WindowCommand(MainWindow window)
{
_window = window;
}
//always called before executing the command, mine just always returns true
public bool CanExecute(object parameter)
{
return true; //mine always returns true, yours can use a new CanExecute delegate, or add custom logic to this method instead.
}
public event EventHandler CanExecuteChanged; //i'm not using this, but it's required by the interface
//the important method that executes the actual command logic
public void Execute(object parameter)
{
if (ExecuteDelegate != null)
{
ExecuteDelegate();
}
else
{
throw new InvalidOperationException();
}
}
}
同様の問題があり、@ aliwaの回答が最も役立つ最もエレガントなソリューションであることがわかりました。ただし、特定のキーの組み合わせCtrl+が必要でした1。残念ながら、次のエラーが発生しました。
「1」は「キー」の値として使用できません。数値は有効な列挙値ではありません。
少し検索して、@ aliwaの回答を次のように変更しました。
<Window.InputBindings>
<KeyBinding Gesture="Ctrl+1" Command="{Binding MyCommand}"/>
</Window.InputBindings>
私はこれが私が必要とするどんな組み合わせでもかなりうまくいくことを発見しました。
<UserControl.InputBindings> <KeyBinding Gesture="Enter" Command="{Binding someCommand}"/> </UserControl.InputBindings>
上位の回答は正解ですがUIElement
、特にWindow
フォーカスする必要のある要素をが認識していない場合は、個人的に添付プロパティを使用してソリューションをany に適用できるようにします。私の経験では、いくつかのビューモデルとユーザーコントロールの構成をよく見ます。ウィンドウは、ルートコンテナーにすぎません。
public sealed class AttachedProperties
{
// Define the key gesture type converter
[System.ComponentModel.TypeConverter(typeof(System.Windows.Input.KeyGestureConverter))]
public static KeyGesture GetFocusShortcut(DependencyObject dependencyObject)
{
return (KeyGesture)dependencyObject?.GetValue(FocusShortcutProperty);
}
public static void SetFocusShortcut(DependencyObject dependencyObject, KeyGesture value)
{
dependencyObject?.SetValue(FocusShortcutProperty, value);
}
/// <summary>
/// Enables window-wide focus shortcut for an <see cref="UIElement"/>.
/// </summary>
// Using a DependencyProperty as the backing store for FocusShortcut. This enables animation, styling, binding, etc...
public static readonly DependencyProperty FocusShortcutProperty =
DependencyProperty.RegisterAttached("FocusShortcut", typeof(KeyGesture), typeof(AttachedProperties), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.None, new PropertyChangedCallback(OnFocusShortcutChanged)));
private static void OnFocusShortcutChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (!(d is UIElement element) || e.NewValue == e.OldValue)
return;
var window = FindParentWindow(d);
if (window == null)
return;
var gesture = GetFocusShortcut(d);
if (gesture == null)
{
// Remove previous added input binding.
for (int i = 0; i < window.InputBindings.Count; i++)
{
if (window.InputBindings[i].Gesture == e.OldValue && window.InputBindings[i].Command is FocusElementCommand)
window.InputBindings.RemoveAt(i--);
}
}
else
{
// Add new input binding with the dedicated FocusElementCommand.
// see: https://gist.github.com/shuebner20/349d044ed5236a7f2568cb17f3ed713d
var command = new FocusElementCommand(element);
window.InputBindings.Add(new InputBinding(command, gesture));
}
}
}
この添付プロパティを使用すると、任意のUIElementのフォーカスショートカットを定義できます。要素を含むウィンドウで入力バインディングを自動的に登録します。
<TextBox x:Name="SearchTextBox"
Text={Binding Path=SearchText}
local:AttachedProperties.FocusShortcutKey="Ctrl+Q"/>
FocusElementCommand実装を含む完全なサンプルは、gistとして入手できます。https://gist.github.com/shuebner20/c6a5191be23da549d5004ee56bcc352d
免責事項:このコードはどこでも無料で使用できます。これは大量の使用には適さないサンプルであることを覚えておいてください。たとえば、コマンドは要素への強い参照を保持するため、削除された要素のガベージコレクションはありません。