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?