为什么 ContextMenuOpen 的源代码对于 Canvas 和 UserControl 的行为不同

本文关键字:UserControl Canvas ContextMenuOpen 源代码 为什么 | 更新日期: 2023-09-27 17:55:41

我有一个简单的窗口:

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:self="clr-namespace:WpfApplication1"
        Title="MainWindow" Height="435" Width="613">
    <StackPanel>
        <Canvas Name="canvas">
            <self:Red />
        </Canvas>
        <UserControl Name="uc">
            <self:Blue />
        </UserControl>
    </StackPanel>
</Window>

RedBlue非常简单UserControls

<UserControl x:Class="WpfApplication1.Blue"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">
    <Grid>
        <Rectangle Fill="Blue" Width="100" Height="100" />
    </Grid>
</UserControl>

我创建了一些上下文菜单:

public MainWindow()
{
    InitializeComponent();
    canvas.ContextMenu = new ContextMenu();
    canvas.ContextMenuOpening += (sender, e) =>
    {
        System.Diagnostics.Debug.WriteLine(e.Source.GetType());
    };
    uc.ContextMenu = new ContextMenu();
    uc.ContextMenuOpening += (sender, e) =>
    {
        System.Diagnostics.Debug.WriteLine(e.Source.GetType());
    };
}

如果我在Canvas上打开上下文菜单,SourceRed,但是如果我在UserControl上打开它,SourceUserControl
知道为什么吗?
我在MSDN上找到了这个:

ContextMenu 本身是一个 FrameworkElement 派生类,但此事件不会从作为源打开的上下文菜单中引发。该事件是从"拥有"上下文菜单作为属性的元素引发的...

如果我理解正确Source在第一种情况下应该Canvas,但事实并非如此。

为什么 ContextMenuOpen 的源代码对于 Canvas 和 UserControl 的行为不同

此行为在 RoutedEventArgs.OriginalSource 属性的 MSDN 文档中得到了很好的介绍:

各种元素和内容模型的源调整因类而异。每个调整事件源的类都尝试预测哪个源最有用,用于报告大多数输入方案和该类所针对的方案,然后将该源设置为源。如果此源不是与您处理事件相关的源,请尝试改为检查 OriginalSource,看看它是否报告了更合适的其他源。

这正是UserControl类所做的,它在其AdjustBranchSource()方法中修补Source属性。

因此,正如引用的文本所暗示的那样,您可能正在寻找 OriginalSource 属性以使代码的行为类似,在这两种情况下,您都会获得对矩形的引用。