C# WPF 在 XAML 中添加 KeyBinding 事件

C# WPF add KeyBinding events in XAML

我正在使用 CefSharp 库提供的 ChromiumWebBrowser 向我的 C# 应用程序的用户展示一个网站。

我正在尝试添加功能以允许用户 'zoom in/out' 使用键盘快捷键,即 CTRL +/ CTRL -.

我已成功使用“低级全局键盘挂钩/接收器”向嵌入式浏览器添加 KeyboardListener,网址为:http://www.dylansweb.com/2014/10/low-level-global-keyboard-hook-sink-in-c-net/

目前,我的应用程序将在浏览器上 'zoom in',当浏览器为 'in focus' 并且用户在键盘上按“+”时。我使用以下方法完成了此操作:

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

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

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

但我遇到的问题是:虽然应用程序检测到 'CTRL' 键何时被按下(调试被写入控制台),但它似乎无法检测到按第二个键(“+”键)。

我尝试添加第二个侦听器,它在第一个侦听器内部调用,仅当 leftCtrlDownrightCtrlDown 布尔值中的任何一个为真时(即当用户按下任一 CTRL 键时) ,但应用程序似乎仍未检测到按下第二个键...

如何让我的应用 'listen' 按下另一个键,同时它已经确认当前正在按下一个键?

编辑

我已经尝试按照答案中的建议进行操作,现在 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.csclass如下:

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" />

上面写着:

The name "Zoom" does not exist in the namespace "clr-namespace:Agent".

尽管很明显。

这条线不能用:

<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 方法可用于禁用该命令(因此禁用它绑定到的元素)。

问题是您只挂钩 WM_KEYDOWN 和 WM_SYSKEYDOWN 消息。您还需要挂钩 WM_KEYUP 和 WM_SYSKEYUP 消息。为了确定当前是否按下了 CTRL 键,您必须在他们按下该键时设置您的 leftCtrlDown = true,并在他们释放 键时设置 leftCtrlDown = false。当他们按下控制键以外的任何键时,您的代码会设置 leftCtrlDown = false。这个逻辑是错误的。

查看链接文章,您需要修改 HookCallback() 以侦听 WM_KEYUP 和 WM_SYSKEYUP。然后,您将需要为按下键添加另一个事件,或者在 KeyPressedArgs 中添加一个标志以指示事件是因按下键还是按下键而被触发。不管怎样。