2012-04-13 968 views
1

让我们从元素树开始。最上面的元素是一个WPF窗口,它已经注册了ApplicationCommands.Find命令。 某些子元素具有KeyBinding,并且手势键ENTER指向此命令。这没关系,如果有人按下ENTER键,命令将被执行。 其中我有一个自定义控件,用于搜索和选择一些元素的弹出窗口。在这个地方,虽然, 我不想让自定义控件之外的关键事件冒泡。但我设置e.handled = trueKeyDown += new KeyEventHandler (..),这应该是冒泡路由事件,该自定义控件内的所有控件(文本框等)都将忽略任何类型的输入。 但我只是想停止在CustomControl的级别冒泡,说:从叶子到最顶层的控制父级,而不是进一步! 这是为什么?我不过滤PreviewKeyDown,所以事件必须传播到叶,然后它应该回到父,但它不。WPF防止事件在控件之外冒泡

谢谢

编辑:示例代码:

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

回答

1

你想从您的自定义控制弥合事件到你的窗口,对不对? 然后,您必须重新启动系统窗口中的事件来照顾它。如果您只将其标记为已处理,则意味着不会再采取进一步的行动。

代码应该是这样的:

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对文本框没有太大的作用。否则,你将不得不模拟按键。

+0

不完全。我想停止传播事件到自定义控件的主窗口..但是,谢谢 – 2012-04-17 07:07:40

+0

这就是我所理解的。我认为一些代码可能会有帮助。 – Natxo 2012-04-17 08:26:41

+1

嗨PaN1C,我编辑我的答案后,您的示例代码 – Natxo 2012-04-18 08:51:07