WPF防止控件外的事件冒泡
让我们从元素树开始。最上面的元素是一个WPF窗口,它已注册WPF防止控件外的事件冒泡,wpf,events,routed-commands,Wpf,Events,Routed Commands,让我们从元素树开始。最上面的元素是一个WPF窗口,它已注册ApplicationCommands.Find命令。 某些子元素具有键绑定,且手势键ENTER指向此命令。这是确定的,如果有人按下回车键,命令将被执行。 其中我有一个自定义控件,带有用于搜索和选择某些元素的弹出窗口。但是在这个地方, 我不希望在自定义控件之外允许密钥事件冒泡。但是我为设置了e.handled=true KeyDown+=newkeyeventHandler(..),它应该是一个冒泡路由事件,该自定义控件内的所有控件(文本
ApplicationCommands.Find
命令。
某些子元素具有键绑定,且手势键ENTER指向此命令。这是确定的,如果有人按下回车键,命令将被执行。
其中我有一个自定义控件,带有用于搜索和选择某些元素的弹出窗口。但是在这个地方,
我不希望在自定义控件之外允许密钥事件冒泡。但是我为设置了e.handled=true
KeyDown+=newkeyeventHandler(..)
,它应该是一个冒泡路由事件,该自定义控件内的所有控件(文本框等)将忽略任何类型的输入。
但我只想在CustomControl级别停止冒泡,换句话说:从叶子到最顶端的控件父级,而不是更远!
为什么呢?我没有筛选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");
}
}
/*
*我想在这个水平上停止冒泡。比如说,如果我们在文本框叶的级别上单击“回车”按钮,
*它应该传播到TestUserControl,然后停止。
*/
公共部分类TestUserControl:UserControl
{
公共TestUserControl()
{
初始化组件();
}
}
公共部分类Window6:Window
{
公共窗口6()
{
初始化组件();
}
已执行私有无效命令绑定(对象发送方,已执行路由目标)
{
MessageBox.Show(“已执行”);
}
}
您希望将事件从自定义控件桥接到窗口,对吗?
然后必须从窗口重新启动事件,系统才能处理它。如果只将其标记为已处理,则表示不会采取进一步的操作
代码应该是这样的:
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事件实际上并不意味着按下该键,因为不会进行文本合成
对于您的情况,我的建议是过滤用户控件中的keydown事件,如果
e.Key=Key.Enter,则将其标记为已处理,因为Enter对文本框没有太大作用。否则,您必须模拟按键。不完全如此。我想停止将事件从自定义控件传播到主窗口。。但是谢谢你谢谢你的编辑,但是如果密钥是Key=“f”呢?我无法筛选此键,因为“f”是文本框的有效输入。问题是,我无法强制此控件的用户手动处理KeyDown事件,因为我的控件会出现一些未处理的事件。抓住它,在正确的地方重新起跳。。这不好。你不这么认为吗?用户应该明白,如果他在窗口上放置了一个按键事件的命令,并且需要对其中的任何控件执行不同的行为,那么问题就出在他身上。如果该键是文本框的有效输入,你就必须模拟控件上的按键,你可能会发现如何输入,但我相信这并不简单。