【问题标题】:Event handler on parent catches event from child父事件处理程序捕获子事件
【发布时间】:2015-02-03 07:22:15
【问题描述】:

可能我还没有真正理解 WPF 中的事件系统。

我有一个 TabItem,它的标题由一个 TextBox 和一个 Button 组成。 TextBox 是只读的。 (在真实的应用程序中,它允许双击编辑,但这无关紧要。

选择选项卡很困难,因为 TextBox 会抓取 MouseLeftButtonDown 事件。因此,我向 TabItem 添加了一个事件处理程序,将其置于前台。但是,使用该事件处理程序,按钮不再接收事件。为什么在 TabItem 得到事件之前按钮没有得到事件?我认为它从叶子到逻辑树的根部冒泡。

这是 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>  

下面是代码:

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

【问题讨论】:

    标签: c# wpf events


    【解决方案1】:

    你遇到的事情叫做event routing in WPF。为了防止事件被路由到下一个级别,您必须设置Handled = true。您还可以检查引发此事件的发件人类型以过滤掉不必要的呼叫。

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

    当涉及到用户输入时,有一个非常漂亮的图表显示事件路由 (from MSDN):

    因此,要获得所需的 bottom->up 路由路径,您需要使用 PreviewLeftMouseButtonDown 将行为更改为 Bubble 而不是 Tunnel

    【讨论】:

    • e.Handled = true 放入TabItem_MouseLeftButtonDownEvent() 并没有什么不同;我希望事件首先发生在按钮上,然后发生在包含的 TabItem 上。
    • 感谢 Anatolii,将事件更改为预览类型就可以了。 (我有一本教科书说 MouseLeftButtonDown 将是 Bubble 类型,这似乎是错误的;它还提到 MSDN 显示该策略是直接的)。 我仍然感到困惑。假设 MouseLeftButtonDown 是隧道:当我将 AddHandler (HandledEventsToo) 的第三个参数设置为 false 时,不再调用事件处理程序但按钮接收事件。只有当这是一个冒泡事件时,这对我来说才有意义。
    • 另外:如果是隧道设置 e.Handled 为 false 应该指示事件沿着树向下传播。但这也不会发生。
    • 我有一种强烈的感觉,您面临的问题与您在代码隐藏上创建控制(将检查并确认)这一事实有关。请改用 xaml。
    • 我真正的程序实际上是在 XAML 中。我把它放在代码中,让它更连贯地发布。错误完全相同。你有没有偶然检查过 VS 中的代码?
    猜你喜欢
    • 1970-01-01
    • 2022-06-18
    • 2013-01-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多