How to reference right-clicked object in WPF Context Menu item click event handler?

c#, contextmenu, event-handling, wpf

Solution

note the CommandParameter

<Grid Background="Red" Height="100" Width="100">
    <Grid.ContextMenu>
        <ContextMenu>
            <MenuItem 
                Header="Change status" 
                Click="EditStatusCm_Click"
                CommandParameter="{Binding RelativeSource={RelativeSource Self}, Path=Parent}" />
        </ContextMenu>
    </Grid.ContextMenu>
</Grid>

and use it in the handler to figure out which Grid it is

    private void EditStatusCm_Click(object sender, RoutedEventArgs e)
    {
        MenuItem mi = sender as MenuItem;
        if (mi != null)
        {
            ContextMenu cm = mi.CommandParameter as ContextMenu;
            if (cm != null)
            {
                Grid g = cm.PlacementTarget as Grid;
                if (g != null)
                {
                    Console.WriteLine(g.Background); // Will print red
                }
            }
        }
    }

Update: If you want the menuitem handler to get to the Grid's children instead of the Grid itself, use this approach

<Grid Background="Red" Height="100" Width="100">
    <Grid.Resources>
        <ContextMenu x:Key="TextBlockContextMenu">
            <MenuItem 
                Header="Change status" 
                Click="EditStatusCm_Click"
                CommandParameter="{Binding RelativeSource={RelativeSource Self}, Path=Parent}" />
        </ContextMenu>

        <Style TargetType="{x:Type TextBlock}">
            <Setter Property="ContextMenu" Value="{StaticResource TextBlockContextMenu}" />
        </Style>
    </Grid.Resources>

    <Grid.RowDefinitions>
        <RowDefinition />
        <RowDefinition />
    </Grid.RowDefinitions>

    <TextBlock Text="Row0" Grid.Row="0" />
    <TextBlock Text="Row1" Grid.Row="1" />
</Grid>

Just replace the TextBlocks with whatever your custom object type is. Then in the event handler, replace `Grid g = cm.PlacementTarget as Grid` with `TextBlock t = cm.PlacementTarget as TextBlock` (or whatever your custom object type is).

Problem

In WPF application there is a `Grid` with a number of objects (they are derived from a custom control). I want to perform some actions on each of them using context menu: ``` <Grid.ContextMenu> <ContextMenu> <MenuItem Name="EditStatusCm" Header="Change status" Click="EditStatusCm_Click"/> </ContextMenu> </Grid.ContextMenu> ``` But in the event handler I cannot get know which of the objects was right-clicked: ``` private void EditStatusCm_Click(object sender, RoutedEventArgs e) { MyCustControl SCurrent = new MyCustControl(); MenuItem menu = sender as MenuItem; SCurrent = menu.DataContext as MyCustControl; // here I get a run-time error SCurrent.Status = MyCustControl.Status.Sixth; } ``` On that commented line Debugger says: Object reference not set to an instance of an object. Please help, what is wrong in my code? Edited (added): I tried to do the same, using Command approach: I declared a `DataCommands` Class with `RoutedUICommand Requery` and then used `Window.CommandBindings` ``` <Window.CommandBindings> <CommandBinding Command="MyNamespace:DataCommands.Requery" Executed="RequeryCommand_Executed"></CommandBinding> </Window.CommandBindings> ``` XAML of MenuItem now looks like: ``` <Grid.ContextMenu> <ContextMenu> <MenuItem Name="EditStatusCm" Header="Change status" Command="MyNamespace:DataCommands.Requery"/> </ContextMenu> </Grid.ContextMenu> ``` And event handler looks like: ``` private void RequeryCommand_Executed(object sender, ExecutedRoutedEventArgs e) { IInputElement parent = (IInputElement)LogicalTreeHelper.GetParent((DependencyObject)sender); MyCustControl SCurrent = new MyCustControl(); SCurrent = (MuCustControl)parent; string str = SCurrent.Name.ToString();// here I get the same error MessageBox.Show(str); } ``` But debugger shows the same run-time error: Object reference not set to an instance of an object. What is missing in my both approaches? How I should reference right-clicked object in WPF Context Menu item click event handler?

Original source