简体   繁体   English

C#WPF在XAML中添加KeyBinding事件

[英]C# WPF add KeyBinding events in XAML

I am displaying a website to users of my C# application using a ChromiumWebBrowser provided by the CefSharp library. 我正在使用CefSharp库提供的ChromiumWebBrowser向我的C#应用​​程序的用户显示一个网站。

I am trying to add functionality to allow the users to 'zoom in/out' using keyboard shortcuts, ie CTRL + / CTRL - . 我正在尝试添加功能,以允许用户使用键盘快捷键(即CTRL + / CTRL - “放大/缩小”。

I have managed to add a KeyboardListener to 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 ,该网址位于: http : //www.dylansweb.com/2014/10/low-level-global-keyboard-hook-sink-网络内/

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: 我使用<Grid>上的<KeyBinding>标记调用此方法,浏览器在其中显示在我的XAML中:

<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 leftCtrlDown or rightCtrlDown booleans are true (ie when the user is pressing either CTRL key), but the application still doesn't seem to detect the press of a second key... 我尝试添加第二个侦听器,仅当leftCtrlDownrightCtrlDown布尔值中的任何一个为true时(即,当用户按下任一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.cs class 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". 名称“ Zoom”在名称空间“ clr-namespace:Agent”中不存在。

even though it clearly does. 即使很明显。

This line can't work: 该行不起作用:

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

KeyBinding.Command expects an object implementing ICommand , you are binding it to a method. KeyBinding.Command需要一个实现ICommand的对象,您将其绑定到方法。

A basic implementation of the ICommand interface 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 Commanding to define the Command in code and use it in XAML. 通常,您将使用Commanding在代码中定义Command并在XAML中使用它。 When you bind that Command to a KeyBinding , Button or MenuItem (or something else), the CanExecute method of your implementation can be used to disable the command (and therefore disabling the Element it's bound to). 当您将该命令绑定到KeyBindingButtonMenuItem (或其他)时,实现的CanExecute方法可用于禁用命令(并因此禁用其绑定的Element)。

The problem is that you are only hooking the WM_KEYDOWN and WM_SYSKEYDOWN messages. 问题是您只钩住WM_KEYDOWN和WM_SYSKEYDOWN消息。 You need to also hook the WM_KEYUP and WM_SYSKEYUP messages. 您还需要挂钩WM_KEYUP和WM_SYSKEYUP消息。 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 release the key. 为了确定当前是否按下了CTRL键,您必须在按下键时将leftCtrlDown = true设置,并在释放键时将leftCtrlDown = false设置。 Your code sets leftCtrlDown = false when they press any key other than control. 当您按下控件以外的任何键时,您的代码设置leftCtrlDown = false。 That logic is incorrect. 这种逻辑是不正确的。

Looking at the linked article, you will need to modify HookCallback() to listen for WM_KEYUP and WM_SYSKEYUP. 查看链接的文章,您将需要修改HookCallback()来侦听WM_KEYUP和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. 然后,您将需要添加另一个事件以进行按键激活,或者在FlagPressedArgs中添加一个标志以指示该事件是针对按键激活还是按键按下而触发的。 Either way. 无论哪种方式。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM