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' 键何时被按下(调试被写入控制台),但它似乎无法检测到按第二个键(“+”键)。
我尝试添加第二个侦听器,它在第一个侦听器内部调用,仅当 leftCtrlDown
或 rightCtrlDown
布尔值中的任何一个为真时(即当用户按下任一 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.cs
class如下:
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 中使用它。当您将该命令绑定到 KeyBinding
、Button
或 MenuItem
(或其他东西)时,您实现的 CanExecute
方法可用于禁用该命令(因此禁用它绑定到的元素)。
问题是您只挂钩 WM_KEYDOWN 和 WM_SYSKEYDOWN 消息。您还需要挂钩 WM_KEYUP 和 WM_SYSKEYUP 消息。为了确定当前是否按下了 CTRL 键,您必须在他们按下该键时设置您的 leftCtrlDown = true,并在他们释放 键时设置 leftCtrlDown = false。当他们按下控制键以外的任何键时,您的代码会设置 leftCtrlDown = false。这个逻辑是错误的。
查看链接文章,您需要修改 HookCallback() 以侦听 WM_KEYUP 和 WM_SYSKEYUP。然后,您将需要为按下键添加另一个事件,或者在 KeyPressedArgs 中添加一个标志以指示事件是因按下键还是按下键而被触发。不管怎样。
我正在使用 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' 键何时被按下(调试被写入控制台),但它似乎无法检测到按第二个键(“+”键)。
我尝试添加第二个侦听器,它在第一个侦听器内部调用,仅当 leftCtrlDown
或 rightCtrlDown
布尔值中的任何一个为真时(即当用户按下任一 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.cs
class如下:
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 中使用它。当您将该命令绑定到 KeyBinding
、Button
或 MenuItem
(或其他东西)时,您实现的 CanExecute
方法可用于禁用该命令(因此禁用它绑定到的元素)。
问题是您只挂钩 WM_KEYDOWN 和 WM_SYSKEYDOWN 消息。您还需要挂钩 WM_KEYUP 和 WM_SYSKEYUP 消息。为了确定当前是否按下了 CTRL 键,您必须在他们按下该键时设置您的 leftCtrlDown = true,并在他们释放 键时设置 leftCtrlDown = false。当他们按下控制键以外的任何键时,您的代码会设置 leftCtrlDown = false。这个逻辑是错误的。
查看链接文章,您需要修改 HookCallback() 以侦听 WM_KEYUP 和 WM_SYSKEYUP。然后,您将需要为按下键添加另一个事件,或者在 KeyPressedArgs 中添加一个标志以指示事件是因按下键还是按下键而被触发。不管怎样。