Why does Source for ContextMenuOpening behave differently for Canvas and UserControl?

129 views Asked by At

I have a simple window:

<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>

Redand Blueare very simple 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>

I have created some ContextMenus:

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

If I open the context menu on the Canvas, the Source is Red, but if I open it on the UserControl, Source is UserControl.
Any idea why?
I found this on MSDN:

ContextMenu itself is a FrameworkElement derived class, but this event will not be raised from the context menu being opened as a source. The event is raised from the element that "owns" the context menu as a property...

If I understand it correctly Source should be Canvas in the first case, but it isn't.

1

There are 1 answers

2
Hans Passant On BEST ANSWER

This behavior is covered fairly well in the MSDN documentation for the RoutedEventArgs.OriginalSource property:

Source adjustment by various elements and content models varies from class to class. Each class that adjusts event sources attempts to anticipate which source is the most useful to report for most input scenarios and the scenarios for which the class is intended, and then sets that source as the Source. If this source is not the one that has relevance to your handling of the event, try checking OriginalSource instead to see if it reports a different source that is more suitable.

Which is exactly what the UserControl class does, it patches the Source property in its AdjustBranchSource() method.

So, as hinted by the quoted text, you are perhaps looking for the OriginalSource property to make the code behave similarly, you'll get a reference to the Rectangle in both cases.