C# WPF 在 XAML 中添加 KeyBinding 事件

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/37722559/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-13 13:50:21  来源:igfitidea点击:

C# WPF add KeyBinding events in XAML

c#wpfxamlkeyboard-shortcutskeypress

提问by Noble-Surfer

I am displaying a website to users of my C# application using a ChromiumWebBrowserprovided by the CefSharplibrary.

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

I am trying to add functionality to allow the users to 'zoom in/out' using keyboard shortcuts, i.e. CTRL +/ CTRL -.

我正在尝试添加功能以允许用户使用键盘快捷键(即CTRL +/ )“放大/缩小” CTRL -

I have managed to add a KeyboardListenerto the embedded browser using the 'Low Level Global Keyboard Hook/ Sink available at: http://www.dylansweb.com/2014/10/low-level-global-keyboard-hook-sink-in-c-net/

我已设法KeyboardListener使用“低级全局键盘挂钩/接收器”将 a 添加到嵌入式浏览器:http: //www.dylansweb.com/2014/10/low-level-global-keyboard-hook-sink-in -c-net/

At the moment, my application will 'zoom in' on the browser, when the browser is 'in focus', and the user presses '+' on the keyboard. I've done this using:

目前,当浏览器处于“焦点”状态时,我的应用程序将“放大”浏览器,并且用户按下键盘上的“+”。我已经这样做了:

private void _listener_OnKeyPressed(object sender, KeyPressedArgs e)
{
    if(e.KeyPressed == Key.Add)
    {
        zoomInExecuted();
    }
}

What I actually want, is only to allow the zoom in when the users holds either 'CTRL' key down, and then presses '+'.

我真正想要的是,仅当用户按住“CTRL”键,然后按“+”时才允许放大。

I've written the following method in my C# (this is the method being called:

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

I'm calling this method using the <KeyBinding>tag on the <Grid>in which the browser is displayed in my XAML:

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

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

But the problem I'm having with this is: although the application detects when the 'CTRL' key is pressed (the debug is written to the console), it seems that it then can't detect the press on the second key (the '+' key).

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

I tried adding a second listener, that is called inside the first listener, only when either of the leftCtrlDownor rightCtrlDownbooleans are true (i.e. when the user is pressing either CTRL key), but the application still doesn't seem to detect the press of a second key...

我尝试添加第二个侦听器,在第一个侦听器中调用,仅当 theleftCtrlDownrightCtrlDownbooleans 为真时(即当用户按下任一 CTRL 键时),但应用程序似乎仍未检测到按下第二把钥匙...

How can I make my app 'listen' for a press to another key, while it's already acknowledging that one key is currently being pressed down?

如何让我的应用程序“监听”按下另一个键,同时它已经确认当前正在按下一个键?

Edit

编辑

I've tried doing what was suggested in the answer, and now have in my XAML:

我试过按照答案中的建议去做,现在在我的 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>

The Zoom.csclass that I've added is as follows:

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

But for some reason, I'm getting a compile error in the XAML, on the line:

但是出于某种原因,我在 XAML 中遇到了编译错误,就行:

                                            <local:Zoom Executed="zoomInExecuted" />

which says:

其中说:

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

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

even though it clearly does.

尽管它显然是。

回答by Manfred Radlwimmer

This line can't work:

这条线不能工作:

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

KeyBinding.Commandexpects an object implementing ICommand, you are binding it to a method.

KeyBinding.Command期望一个对象实现ICommand,你将它绑定到一个方法。

A basic implementation of the ICommandinterface would look something like this:

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

Which you could use like this:

你可以这样使用:

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

And in code behind:

在后面的代码中:

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

Usually you would use Commandingto define the Command in code and use it in XAML. When you bind that Command to a KeyBinding, Buttonor MenuItem(or something else), the CanExecutemethod of your implementation can be used to disable the command (and therefore disabling the Element it's bound to).

通常您会使用Commanding在代码中定义 Command 并在 XAML 中使用它。当您绑定该命令的KeyBindingButtonMenuItem(或别的东西),在CanExecute你的实现方法可用于禁用指令(因此禁用元素,它绑定到)。

回答by Moby Disk

The problem is that you are only hooking the WM_KEYDOWN and WM_SYSKEYDOWN messages. You need to also hook the WM_KEYUP and WM_SYSKEYUP messages. In order to determine if the CTRL key is currently being pressed, you must set you leftCtrlDown = true when they press the key, and set leftCtrlDown = false when they releasethe key. Your code sets leftCtrlDown = false when they press any key other than control. That logic is incorrect.

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

Looking at the linked article, you will need to modify HookCallback() to listen for WM_KEYUP and WM_SYSKEYUP. Then you will either need to add another event for key up, or add a flag into the KeyPressedArgs to indicate if the event is being fired for key up or key down. Either way.

查看链接的文章,您需要修改 HookCallback() 以侦听 WM_KEYUP 和 WM_SYSKEYUP。然后,您需要为按键添加另一个事件,或者在 KeyPressedArgs 中添加一个标志,以指示该事件是为按键向上还是按键向下触发。无论哪种方式。