为什么PreviewMouseLeftButtonDownEvent中的Handled属性会影响ClickEvent ?



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

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

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

如果您在预览中设置了e.Handled = true…-Event, Click-Event不再被处理

然而,现在让我们考虑一下MouseLeftButtonDownEvent。
首先,该事件的路由策略是直接的。也就是说,它会为每个控件重新引发。相比之下,预览版…事件是隧道,点击事件是冒泡。
其次,添加MouseLeftButtonDownEventHandler只有在注册处理程序时才会成功,这样它甚至可以为已经处理的事件调用,如下面的代码摘录所示。

button.AddHandler(MouseLeftButtonDownEvent,
                  new MouseButtonEventHandler(Button_MouseLeftButtonDown),
                  true);
我已经编写了一个测试应用程序,有一个按钮,并为每个事件添加了一个处理程序。当调用事件处理程序时,它将一些信息写入文本块。
  • 当我单击该按钮时,调用所有三个事件处理程序。
  • 当我添加e.Handled = true到预览…-EventHandler,只调用这个事件处理程序。即使是老鼠……-EventHandler没有被引发,尽管我已经将UIElement.AddHandler handledEventsToo设置为true。
  • 当我添加e.Handled = true到鼠标…-EventHandler,三个事件处理程序都被调用。

那对我来说没有任何意义。鼠标……-EventHandlers不影响Click-EventHandlers,但预览…- eventhandler影响两个鼠标…-和click - eventandlers .
甚至'强制'处理鼠标失败的事件…-EventHandler.

实际上,我从来没有想过不同类型的事件处理程序会相互影响。我所理解的是,如果我有一个预览…-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);
}

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

你基本上是正确的,因为这是相当罕见的,但你可以在MSDN的预览事件页面找到你的答案。从链接页面:

例如,Windows Presentation Foundation (WPF)按钮抑制由按钮或其复合元素引发的MouseLeftButtonDown和MouseLeftButtonDown气泡事件,以支持捕获鼠标并引发始终由按钮本身引发的Click事件。事件和它的数据仍然沿着路由继续,但是由于Button将事件数据标记为Handled,所以只调用那些明确指出应该在handledeventtoo情况下起作用的事件处理程序。

此外,你还说:

当我给鼠标添加e.Handled = true…-EventHandler,所有三个事件处理程序都被调用

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

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

相关内容

  • 没有找到相关文章

最新更新