如何覆盖默认的“全局”键盘快捷键并创建自己的快捷键?

3
我了解WPF中基本的事件路由/冒泡(显然还不够)...我想做的是在我的WPF桌面应用程序中使用基本的键盘快捷键。例如,我有一个ListBox,当用户按下Page-Up或Page-Down(应用程序中可能会聚焦任何内容)时,如果适用,我希望ListBox选择其上一个或下一个项目。
这是我目前拥有的,但它不起作用。这是一个名为“Main”的窗口的构造函数:
public Main()
{
    InitializeComponent();

    // Initialize keyboard shortcuts
    KeyDown += (s, e) =>
    {
        var viewModel = GetActiveViewModel();
        if (e.Key == Key.PageUp)
        {
            viewModel.SelectPreviousItem();
            e.Handled = true;
        }
        else if (e.Key == Key.PageDown)
        {
            viewModel.SelectNextItem();
            e.Handled = true;
        }
    };
}

这段代码本应该起作用,但是当前活动控件“夺取”了事件并实现了默认行为,例如如果我选择了文本框,则文本框会移动光标,如果我选择了列表框,则列表框会将选定的索引向前或向后移动一个“页面”,而不是像我想要的那样移动单个项目。

我该如何指示WPF“忽略”任何默认键盘钩子,并替换为自己的逻辑?我理解我将要“覆盖”某些控件的默认行为(例如,在文本框中按下Page-Up/Page-Down将不再移动光标),这没问题,这正是我想要的。


4
永远记住“最小惊讶原则”。如果我在一个应用程序中按“Page Up”按钮,而它只向上移动一项,我会感到困惑和恼怒。我按Page Up是因为我想要向上翻一页。 - Daniel Mann
这些不是我的要求,而是一个商业应用程序的要求。我理解用户体验原则,但我需要实现它。如果这让你感觉更好,可以假装快捷键将是Ctrl+PageUp。;) - qJake
2个回答

5
你可以注册 PreviewKeyDown 事件来实现你的需求。
在 WPF 中,每个控件都可以有一个默认的事件实现,并且将 "Handled" 属性设置为 true,这告诉 WPF 的可视树停止传播该事件。
试试这个方法:
PreviewKeyDown += (s, e) =>
{
   var viewModel = GetActiveViewModel();
   if (e.Key == Key.PageUp)
   {
      viewModel.SelectPreviousItem();
      e.Handled = true;
   }
   else if (e.Key == Key.PageDown)
   {
      viewModel.SelectNextItem();
      e.Handled = true;
   }
};

-1

那样做不会完全起作用。

您需要通过在此处找到的操作系统注册的全局热键进行隧道通信 here:

使用KEYBOARD_LL挂钩Win32操作系统代码

SetWindowsHookEx((int) HookType.WH_KEYBOARD_LL, _keyboardProc, moduleHandler, 0);

我曾为一家公司这样做,其中我将WPF CommandBindings包装成WF -> Win32 LL。

像Ctl + Alt + Del这样的几个最大的热键可以从注册表中删除,并删除屏幕上的所有选项,例如注销,任务管理器等。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接