在C# WPF中,如何在XAML中添加KeyBinding事件

3
我正在使用由CefSharp库提供的ChromiumWebBrowser向我的C#应用程序用户展示网站。
我正在尝试添加功能,允许用户使用键盘快捷键进行“缩放”,即CTRL + / CTRL -。
我已成功向嵌入式浏览器添加了KeyboardListener,使用“低级全局键盘钩子/接收器”,可在http://www.dylansweb.com/2014/10/low-level-global-keyboard-hook-sink-in-c-net/中找到。
目前,当浏览器处于“焦点”状态时,用户按下键盘上的“+”键,我的应用程序将“放大”浏览器。我是通过以下方式实现的:
private void _listener_OnKeyPressed(object sender, KeyPressedArgs e)
{
    if(e.KeyPressed == Key.Add)
    {
        zoomInExecuted();
    }
}

我实际想要的是,只有当用户按住“CTRL”键并按下“+”键时才允许缩放。

我在我的C#中编写了以下方法(这是被调用的方法):

private void _listener_OnKeyPressed(object sender, KeyPressedArgs e)
{
    Debug.WriteLine("e: " + e.KeyPressed.ToString());

    if(e.KeyPressed == Key.LeftCtrl)
    {
        leftCtrlDown = true;
        Debug.WriteLine("LeftCtrl pressed, leftCtrlDown should be true: ", leftCtrlDown.ToString());
    }
    else
    {
        leftCtrlDown = false;
    } 

    if(e.KeyPressed == Key.RightCtrl)
    {
        rightCtrlDown = true;
        Debug.WriteLine("RightCtrl pressed, rightCtrlDown should be true: ", rightCtrlDown.ToString());
    }
    else
    {
        rightCtrlDown = false;
    }

    if((leftCtrlDown == true)) //&& (e.KeyPressed == Key.Add)) 
    {
        if (e.KeyPressed == Key.Add)
        {
            Debug.WriteLine("Ctrl & + pressed, 'zoomInExecuted()' should be called ");
            zoomInExecuted();
        }
    }else if((rightCtrlDown == true)) //&& (e.KeyPressed == Key.Add))
    {
        if (e.KeyPressed == Key.Add)
        {
            Debug.WriteLine("rightCtrl & + pressed, 'zoomInExecuted()' should be called ");
            zoomInExecuted();
        }
    }
}

我正在使用XAML中显示浏览器的<Grid>标签上的<KeyBinding>标签来调用此方法:

<KeyBinding Modifiers="Ctrl" Key="LeftCtrl" Command="{Binding _listener_OnKeyPressed}"></KeyBinding>

但我遇到的问题是:虽然应用程序可以检测到按下“CTRL”键(调试信息写入控制台),但似乎它无法检测第二个键(“+”键)的按下。
我尝试添加了第二个侦听器,在第一个侦听器内调用,仅当leftCtrlDownrightCtrlDown布尔值为true时(即用户按下任一CTRL键时),但应用程序仍然似乎无法检测第二个键的按下...
在已经确认有一个键被按下的情况下,如何使我的应用程序“监听”另一个键的按下?
编辑
我已经尝试了答案中建议的方法,并在我的XAML中添加了以下内容:
<Window x:Class="..."
    ....
    xmlns:local="clr-namespace:Agent"
    ... >

    <Window.Resources>
        ...
    </Window.Resources>
    <Grid Name="grid">
        ...
        <Grid x:Name="grdBrowserHost" MinHeight="900" Height="Auto" MinWidth="1205" Width="Auto" Margin="5,0,0,0" DockPanel.Dock="Bottom" Grid.ColumnSpan="1" >
            <Grid.InputBindings>
                <KeyBinding Modifiers="Ctrl" Key="Add" Command="{Binding _listener_OnKeyPressed}"></KeyBinding>
            </Grid.InputBindings>
            ...
            <cefSharp:ChromiumWebBrowser Name="browser" ...>
                <KeyBinding Modifiers="Ctrl" Key="Add">
                    <KeyBinding.Command>
                        <local:Zoom Executed="zoomInExecuted" />
                    </KeyBinding.Command>
                </KeyBinding>
            </cefSharp:ChromiumWebBrowser.InputBindings>
        </Grid>
    </Grid>
    ...
</Window>

我添加的Zoom.cs类如下:

namespace Agent
{
    class Zoom : ICommand
    {
        public event EventHandler<object> Executed;

        public bool CanExecute(object parameter)
        {
            return true;
        }

        public void Execute(object parameter)
        {
            if (Executed != null)
                Executed(this, parameter);
        }

        public event EventHandler CanExecuteChanged;
    }
}

但出于某种原因,我在XAML中的这一行代码上遇到了编译错误:

                                            <local:Zoom Executed="zoomInExecuted" />

内容如下:

名称“Zoom”在命名空间“clr-namespace:Agent”中不存在。

尽管它明显存在。


LeftCtrl 也是一个修饰键,你不能为 Ctrl + LeftCtrl 设置快捷键。 - Manfred Radlwimmer
你是指在XAML中吗?我已经尝试将其更改为:<KeyBinding Modifiers="Ctrl" Key="Add" Command="{Binding _listener_OnKeyPressed}"></KeyBinding>,但我仍然遇到了同样的问题...我的控制台显示当我按下CTRL时,CTRL被按下,然后显示当我按下+时,+被按下,但zoomInExecuted()函数似乎没有被调用... - Noble-Surfer
2
Zoom 可能需要公开。 - Moby Disk
2个回答

11

这一行无法正常工作:

<KeyBinding Modifiers="Ctrl" Key="LeftCtrl" Command="{Binding _listener_OnKeyPressed}"/>

KeyBinding.Command期望一个实现ICommand接口的对象,你正在将其绑定到一个方法上。

实现ICommand接口的基本方法应该如下所示:

class SimpleCommand : ICommand
{
    public event EventHandler<object> Executed;

    public bool CanExecute(object parameter)
    {
        return true;
    }

    public void Execute(object parameter)
    {
        if (Executed != null)
            Executed(this, parameter);
    }

    public event EventHandler CanExecuteChanged;
}

你可以像这样使用:

<Window.InputBindings>
    <KeyBinding Modifiers="Control" Key="Add">
       <KeyBinding.Command>
           <local:SimpleCommand Executed="SimpleCommand_OnExecuted"/>
       </KeyBinding.Command>
    </KeyBinding>
</Window.InputBindings>

在后台代码中:

private void SimpleCommand_OnExecuted(object sender, object e)
{
    MessageBox.Show("SimpleCommand Executed");
}

通常,您会使用命令 (Commanding)在代码中定义命令并在XAML中使用。当将该命令绑定到KeyBindingButtonMenuItem(或其他某些元素)时,您的实现的CanExecute方法可用于禁用该命令(因此禁用其绑定的元素)。


谢谢你的回答。我有的代码“可以工作”,但只有当我想让键盘快捷键只由一个键组成时才行-也就是说,如果我在按下键盘上的“+”时调用“缩放”方法,GUI上显示的视图将会放大-我正在寻找的是一种只在同时按下“CTRL”和“+”时调用此事件的方法。我不明白你在回答中编写的代码如何解决这个问题?你能进一步解释一下吗? - Noble-Surfer
看了你的代码,似乎我的类必须从 ICommand 继承?但是我无法这样做,因为我已经从 Window 继承了,由于应用程序提供的其他功能。我该如何在现有代码中使用 ICommand?当使用键盘时将 ICommand 传递给我的应用程序与传递方法有什么不同? - Noble-Surfer
什么?不是的!窗口不必继承自ICommand。你的命令必须继承自它。我已经提供了一个简单的实现(SimpleCommand)。你只需按照那个模式,用你自己的事件处理程序替换SimpleCommand_OnExecuted,比如ZoomIn_OnExecuted - Manfred Radlwimmer
你写的 class SimpleCommand : ICommand 代码块是什么意思?这让我想到我需要让我的类继承 ICommand 接口... 我需要编写一个实现 ICommand 接口的类,然后在 XAML 中通过 CTRL+ 键调用它吗?我不知道/不明白我应该如何实现你在 class SimpleCommand 中编写的代码? - Noble-Surfer
只需将其放入 .cs 文件中,在 xaml 中引用命名空间(xmlns:local=whatever),然后使用它。 - Manfred Radlwimmer
显示剩余4条评论

1
问题在于您只钩取了WM_KEYDOWN和WM_SYSKEYDOWN消息。你还需要钩取WM_KEYUP和WM_SYSKEYUP消息。为了确定CTRL键是否正在被按下,当他们按下该键时,必须将leftCtrlDown设置为true,并在他们释放该键时将leftCtrlDown设置为false。您的代码在按下除控制键以外的任何键时都会将leftCtrlDown设置为false。这个逻辑是错误的。
查看链接的文章,您需要修改HookCallback()以便监听WM_KEYUP和WM_SYSKEYUP。然后,您要么需要添加另一个用于键抬起的事件,要么将一个标志添加到KeyPressedArgs中,以指示事件是为键按下还是键抬起而触发的。无论哪种方式。

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