Wpf 为什么PreviewMouseLeftButtonDownEvent中的已处理属性会影响ClickEvent?

Wpf 为什么PreviewMouseLeftButtonDownEvent中的已处理属性会影响ClickEvent?,wpf,events,event-handling,eventhandler,routedevent,Wpf,Events,Event Handling,Eventhandler,Routedevent,考虑为按钮添加ClickEvent和PreviewMouseLeftButtonDown处理程序 <Button x:Name="button" Click="Button_Click" PreviewMouseLeftButtonDown="Button_PreviewMouseLeftButtonDown"> </Button> 我已经编写了一个测试应用程序,它有一个按钮,并为每个事件添加了一个处理程序。调用事件处理程序时,它会将一些信息写入文本块

考虑为按钮添加ClickEvent和PreviewMouseLeftButtonDown处理程序

<Button x:Name="button"
    Click="Button_Click"
    PreviewMouseLeftButtonDown="Button_PreviewMouseLeftButtonDown">
</Button>
我已经编写了一个测试应用程序,它有一个按钮,并为每个事件添加了一个处理程序。调用事件处理程序时,它会将一些信息写入文本块

  • 单击该按钮时,将调用所有三个事件处理程序
  • 当我将
    e.Handled=true
    添加到Preview…-EventHandler时,仅调用此事件处理程序。即使是鼠标…-EventHandler也不会引发,尽管我已将
    UIElement.addhandledhandledeventstoo
    设置为true
  • 当我将
    e.Handled=true
    添加到鼠标…-EventHandler时,将调用所有三个事件处理程序
这对我来说毫无意义。鼠标…-事件处理程序不影响单击事件处理程序,但预览…-事件处理程序同时影响鼠标…-和单击事件处理程序。
甚至“强制”处理鼠标事件也失败了…-EventHandler

事实上,我从未想过不同类型的事件处理程序会相互影响。我的理解是,如果我有一个预览…-事件和一个点击事件,它们是独立的

那么,我错过了什么


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

XAML:

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

您基本上是正确的,因为这是非常罕见的,但您可以在MSDN页面上找到您的答案。从链接页面:

例如,Windows演示基础(WPF)按钮抑制按钮或其复合元素所引发的MouSelftButoDon和MouSelfutButton Buffin事件,有利于捕获鼠标并引发按钮本身总是引发的点击事件。事件及其数据仍沿路径继续,但由于按钮将事件数据标记为已处理,因此仅调用专门指示它们应在HandledEventsTo案例中操作的事件处理程序

此外,你说:

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

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

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


这是否意味着,鼠标和单击都是要预览的“对应项”。然而,点击是一种替代/继续鼠标的行为?也就是说,预览会影响鼠标和单击,因为两者都在观看预览的处理道具。单击忽略鼠标的已处理状态,但不忽略预览状态。因此,单击仅受预览影响,而不受鼠标影响。此外,HandledEventsTo只影响相同类型的事件对吗?如果是,我想知道是否有一种方法可以为冒泡事件调用事件处理程序,即使隧道事件设置为true?
button.AddHandler(MouseLeftButtonDownEvent,
                  new MouseButtonEventHandler(Button_MouseLeftButtonDown),
                  true);
<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);
}