【问题标题】:Why does the Handled property in PreviewMouseLeftButtonDownEvent affect a ClickEvent?为什么 PreviewMouseLeftButtonDown 事件中的 Handle 属性会影响 Click 事件?
【发布时间】:2014-08-06 09:14:57
【问题描述】:

考虑为按钮添加 ClickEvent- 和 PreviewMouseLeftButtonDown-Handler

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

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

如果您在 Preview...-Event 中设置 e.Handled = true,则不再处理 Click-Event。

但是,现在让我们考虑一下 MouseLeftButtonDownEvent。
首先,这个事件的路由策略是直接的。也就是说,每次控制都会重新加注。相比之下,Preview...-Event 是隧道式的,Click-Event 是冒泡的。
其次,添加 MouseLeftButtonDownEventHandler 仅在注册处理程序时才成功,以便甚至为已处理的事件调用它,如以下代码摘录所示。

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

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

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

这对我来说没有任何意义。 Mouse...-EventHandlers 不会影响 Click-EventHandlers,但 Preview...-EventHandlers 会影响 Mouse...- 和 Click-EventHandlers。
甚至“强制”处理鼠标事件失败...-EventHandler。

实际上,我从未想过不同类型的事件处理程序会相互影响。我的理解是,如果我有一个 Preview...-Event 和一个 Click-Event,它们是独立的。

那么,我错过了什么?


这是非常简单的示例代码:

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

【问题讨论】:

    标签: wpf events event-handling eventhandler routedevent


    【解决方案1】:

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

    您大部分是正确的,因为这种情况很少见,但您可以在 MSDN 上的Preview Events 页面中找到您的答案。从链接页面:

    例如,Windows Presentation Foundation (WPF) Button 会抑制由 Button 或其复合元素引发的 MouseLeftButtonDown 和 MouseLeftButtonDown 冒泡事件,以便捕获鼠标并引发始终由 Button 本身引发的 Click 事件。事件及其数据仍沿路径继续,但由于 Button 将事件数据标记为已处理,因此仅调用专门指示它们应在handledEventsToo 情况下执行的事件的处理程序。

    另外,你是这么说的:

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

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

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

    【讨论】:

    • 这是否意味着鼠标和单击都是预览的“对应物”。但是,单击是一种替换/继续鼠标?也就是说,Preview 会影响 Mouse 和 Click,因为两者都在观看 Preview 的 Handled 属性。单击会忽略鼠标的已处理状态,但不会忽略预览的状态。因此,单击仅受预览影响,而不受鼠标影响。此外,handledEventsToo 只影响相同类型的事件。 ——这一切都正确吗?如果是,我想知道是否有一种方法可以为冒泡事件调用事件处理程序,即使隧道事件集处理为 true?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-16
    • 2020-12-06
    • 1970-01-01
    • 1970-01-01
    • 2022-11-03
    • 2021-08-03
    相关资源
    最近更新 更多