让我们从元素树开始。最上面的元素是已注册ApplicationCommands.Find
命令的 WPF 窗口。某些子元素具有 KeyBinding,其中的手势键 ENTER 指向此命令。没关系,如果有人按 ENTER 命令将被执行。其中我有一个带有弹出窗口的自定义控件,用于搜索和选择一些元素。不过在这个地方,我不想允许在自定义控件之外冒泡键事件。但我设定了e.handled = true
KeyDown += new KeyEventHandler (..)
,这应该是一个冒泡的路由事件,该自定义控件中的所有控件(文本框等)都将忽略任何类型的输入。但我只想停止在自定义控件级别冒泡,说:从叶子到最上面的控件父级,而不是更进一步!为什么?我没有过滤PreviewKeyDown
,所以事件必须传播到叶子,然后它应该返回到父级,但它没有。
谢谢
已编辑: 示例代码:
<UserControl x:Class="WpfApplication5.TestUserControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
>
<StackPanel Orientation="Vertical">
<TextBox />
<TextBox />
<TextBox />
</StackPanel>
</UserControl>
/*
* I want to stop bubbling at this level. Let us say if we click 'enter' on the level of the TextBox leaf,
* it should propagate until the TestUserControl is reached and then stop.
*/
public partial class TestUserControl : UserControl
{
public TestUserControl()
{
InitializeComponent();
}
}
<Window x:Class="WpfApplication5.Window6"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication5"
Title="Window6" Height="300" Width="300">
<Window.CommandBindings>
<CommandBinding Command="ApplicationCommands.Find" Executed="CommandBinding_Executed" />
</Window.CommandBindings>
<Window.InputBindings>
<KeyBinding Gesture="Enter" Command="ApplicationCommands.Find" />
</Window.InputBindings>
<Grid>
<local:TestUserControl />
</Grid>
</Window>
public partial class Window6 : Window
{
public Window6()
{
InitializeComponent();
}
private void CommandBinding_Executed(object sender, ExecutedRoutedEventArgs e)
{
MessageBox.Show("Executed");
}
}
您希望将事件从自定义控件桥接到窗口,对吗?然后,您必须从窗口重新启动事件,以便系统处理它。如果您仅将其标记为已处理,则意味着不会执行进一步的操作。
代码应该是这样的:
private void CustomControl_KeyDown(object sender, KeyEventArgs e)
{
e.Handled = true;
var relaunchedEvent = new KeyEventArgs(e.KeyboardDevice, e.InputSource, e.Timestamp, e.Key);
relaunchedEvent.RoutedEvent = Keyboard.KeyDownEvent;
relaunchedEvent.Source = e.OriginalSource;
TopMostWindow.RaiseEvent(relaunchedEvent);
}
--编辑--
使用以下 xaml 测试上面的代码,以查看如何在不执行命令的情况下在窗口中触发 keydown 事件。
<Window x:Class="WpfApplication5.Window6"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication5"
Title="Window6" Height="300" Width="300"
x:Name="TopMostWindow">
<Grid>
<Grid KeyDown="CustomControl_KeyDown">
<local:UserControl1/>
</Grid>
<Grid.CommandBindings>
<CommandBinding Command="ApplicationCommands.Find" Executed="CommandBinding_Executed" />
</Grid.CommandBindings>
<Grid.InputBindings>
<KeyBinding Key="Enter" Command="ApplicationCommands.Find" />
</Grid.InputBindings>
</Grid>
</Window>
重要提示:
- 命令处于更高级别,因此无论您使用冒泡事件还是隧道事件,最终都会执行命令,除非事件标记为已处理。
- 引发 Keydown 事件实际上并不意味着按下 Key,因为不会进行文本撰写。
我对你的情况的建议是过滤用户控件中的keydown事件,如果e.Key=Key.Enter
,则将其标记为已处理,因为Enter对文本框没有太大作用。否则,您必须模拟按键。