为什么PreviewMouseLeftButtonDown事件中的Handle属性会影响Click事件?

时间:2014-08-06 09:14:58

标签: wpf events event-handling eventhandler routedevent

考虑为Button添加ClickEvent-和PreviewMouseLeftButtonDown-Handler

<Button x:Name="button"
    Click="Button_Click"
    PreviewMouseLeftButtonDown="Button_PreviewMouseLeftButtonDown">
</Button>

单击Button时,首先触发PreviewMouseLeftButtonDown,然后触发Click-Event。

如果在预览...-事件中设置e.Handled = true,则不再处理Click-Event。

但是,现在让我们想一想MouseLeftButtonDownEvent 首先,此事件的路由策略是直接的。也就是说,它会针对每个控件重新提升。相比之下,预览...... - 事件是隧道,点击事件正在冒泡 其次,只有在注册处理程序时才添加MouseLeftButtonDownEventHandler,以便甚至为已经处理的事件调用它,如以下代码摘录所示。

button.AddHandler(MouseLeftButtonDownEvent,
                  new MouseButtonEventHandler(Button_MouseLeftButtonDown),
                  true);

我编写了一个测试应用程序,有一个按钮,并为每个事件添加了一个处理程序。调用事件处理程序时,它会将一些信息写入文本块。

  • 单击按钮时,将调用所有三个事件处理程序。
  • 当我将e.Handled = true添加到Preview ...- EventHandler时,只调用此事件处理程序。即使是鼠标...... - EventHandler也没有被引发,尽管我已将UIElement.AddHandler handledEventsToo设置为true。
  • 当我将e.Handled = true添加到Mouse ...- EventHandler时,将调用所有三个事件处理程序。

这对我没有任何意义。鼠标...- EventHandlers不会影响Click-EventHandlers,但预览...- EventHandlers会影响鼠标...-和Click-EventHandlers。
甚至'强制'处理事件也失败了鼠标......- EventHandler。

实际上,我从未想过不同类型的事件处理程序会影响彼此。我的理解是,如果我有一个预览...... - 事件和点击事件,这些都是独立的。

那么,我错过了什么?


以下是非常简单的示例代码:

XAML:

<DockPanel>
    <Border x:Name="border" DockPanel.Dock="Top" Height="50"
            BorderBrush="Gray" BorderThickness="1">
        <StackPanel x:Name="stackpanel" Background="LightGray"
                    Orientation="Horizontal" HorizontalAlignment="Center">
            <Button x:Name="button" Width="Auto" 
                    PreviewMouseLeftButtonDown="Button_PreviewMouseLeftButtonDown">
                Click Me
            </Button>
        </StackPanel>
    </Border>
    <Border DockPanel.Dock="Bottom" BorderBrush="Gray" BorderThickness="1">
        <ScrollViewer>
            <TextBlock x:Name="textBlock" TextWrapping="Wrap"/>
        </ScrollViewer>
    </Border>
</DockPanel>

代码隐藏:

public MainWindow()
{
    InitializeComponent();

    button.AddHandler(MouseLeftButtonDownEvent, new MouseButtonEventHandler(Button_MouseLeftButtonDown), true);
    button.AddHandler(ButtonBase.ClickEvent, new RoutedEventHandler(Button_Click), true);
    stackpanel.AddHandler(ButtonBase.ClickEvent, new RoutedEventHandler(Button_Click), true /*false*/ );
}

private void Output(object sender, RoutedEventArgs e)
{
    textBlock.Text += "RoutedEvent: " + e.RoutedEvent + "\n";
    textBlock.Text += "Sender: " + sender + "\n";
    textBlock.Text += "Source: " + e.Source + "\n";
    textBlock.Text += "OriginalSource: " + e.OriginalSource + "\n" + "\n";
}

private void Button_Click(object sender, RoutedEventArgs e)
{
    // e.Handled = true;
    Output(sender, e);
}

private void Button_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
    // e.Handled = true;
    Output(sender, e);
}

private void Button_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
    Output(sender, e);
}

1 个答案:

答案 0 :(得分:2)

  

我从未想过不同类型的事件处理程序会相互影响

您大多是正确的,因为这种情况非常罕见,但您可以在MSDN上的Preview Events页面找到答案。从链接页面:

  

例如,Windows Presentation Foundation(WPF)按钮禁止Button或其复合元素引发的MouseLeftButtonDown和MouseLeftButtonDown冒泡事件,以支持捕获鼠标并引发始终由Button本身引发的Click事件。事件及其数据仍沿着路径继续,但由于Button将事件数据标记为Handled,因此仅调用特定表明它们应在handleEventsToo案例中操作的事件的处理程序。

此外,你说过这个:

  

当我向鼠标...- EventHandler添加e.Handled = true时,会调用所有三个事件处理程序

这是预期的,因为在冒泡事件处理程序中设置e.Handled将不执行任何操作......在事件离开处理程序代码之后,没有任何内容会读取该值。 e.Handled主要用于隧道事件处理程序,以阻止事件进一步路由。再次,从链接页面:

  

对于具体的输入事件,预览事件还与等效的冒泡事件共享事件数据实例。如果使用Preview事件类处理程序标记处理的输入事件,则不会调用冒泡输入事件类处理程序。或者,如果使用预览事件实例处理程序来标记处理的事件,则通常不会调用冒泡事件的处理程序。