简体   繁体   English

父级上的事件处理程序从子级捕获事件

[英]Event handler on parent catches event from child

Probably I have not really understood the event system in WPF. 可能我不太了解WPF中的事件系统。

I have a TabItem that has a header consisting of a TextBox and a Button. 我有一个TabItem,其标题包含一个TextBox和一个Button。 The TextBox is readonly. TextBox是只读的。 ( In the real application it allows editing on double clicking, but that's irrelevant here. ) 在实际的应用程序中,它允许双击进行编辑,但这与此处无关。

It was difficult to select a tab because the TextBox grabs the MouseLeftButtonDown event. 由于TextBox会捕获MouseLeftButtonDown事件,因此很难选择选项卡。 I therefore added an event handler to the TabItem that brings it into foreground. 因此,我在TabItem中添加了一个事件处理程序,将其置于前台。 However with that event handler the button no longer receives the event. 但是,有了该事件处理程序,按钮将不再接收事件。 Why does the button not get the event before the TabItem gets the event? 为什么按钮在TabItem获取事件之前没有获取事件? I thought it bubbles from the leaves to the root of the logical tree. 我以为它从叶子冒泡到逻辑树的根。

Here's the XAML: 这是XAML:

<Window x:Class="tt_WPF.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:tt_WPF"
    Title="MainWindow" SizeToContent="WidthAndHeight">
<TabControl x:Name="TC"></TabControl> 
</Window>  

Here's the code behind: 这是背后的代码:

   public class myItem : TabItem
{
    public myItem(string name)
    {
        // Create horizontal StackPanel
        StackPanel sp = new StackPanel();
        sp.Orientation = Orientation.Horizontal;
        // Create a readonly TextBox
        TextBox tb = new TextBox(); 
        tb.Text = name;
        tb.IsReadOnly = true;
        // Create a Button with a simple command
        Button b = new Button();
        b.Content = "X";
        b.Click += Button_Click;
        // Add Button and TextBlock to StackPanel and StackPanel to this TabIten
        sp.Children.Add(tb);
        sp.Children.Add(b);
        this.Header = sp;
        this.Content = "This is " + name;
        // --> Here's the trouble: Install an event handler that brings the TabItem into foreground when clicked
        this.AddHandler(MouseLeftButtonDownEvent, new RoutedEventHandler(TabItem_MouseLeftButtonDownEvent), true);

    }
    private void Button_Click(object sender, RoutedEventArgs e)
    {
        MessageBox.Show("Button X");
    }
    private void TabItem_MouseLeftButtonDownEvent(object sender, RoutedEventArgs e)
    {
        this.IsSelected = true;
    }
}

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        TC.Items.Add(new myItem("Tab 1"));
        TC.Items.Add(new myItem("Tab 2"));
    }
}

The thing you have faced is called event routing in WPF . 您遇到的事情在WPF中称为事件路由 To prevent event from being routed to the next level you have to set Handled = true . 为了防止事件被路由到下一个级别,您必须设置Handled = true Also you can check for sender type which raised this event to filter out unnecessary calls. 您也可以检查引发此事件的发件人类型,以过滤掉不必要的呼叫。

private void TabItem_MouseLeftButtonDownEvent(object sender, RoutedEventArgs e)
{
    this.IsSelected = true;
    e.Handled = true;
}

There is a very nice diagram displaying events routing when it comes to user input ( from MSDN ): 有一个非常不错的图表,它显示了有关用户输入( 来自MSDN )的事件路由:

事件路由

So to get desired bottom->up routing path you need to change behavior to Bubble instead of Tunnel by using PreviewLeftMouseButtonDown . 因此,要获得所需的自下而上的路由路径,您需要通过使用PreviewLeftMouseButtonDown将行为更改为Bubble而不是Tunnel

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

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