如何在WPF上下文菜单项单击事件处理程序中引用右键单击的对象?

在WPF应用程序中,有一个包含许多对象的Grid (它们来自自定义控件)。 我想使用上下文菜单对每个操作执行一些操作:

       

但是在事件处理程序中,我无法知道哪些对象被右键单击:

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

在该注释行上调试器说: 对象引用未设置为对象的实例。

请帮忙,我的代码有什么问题?

编辑(补充):

我尝试使用Command方法做同样的事情:

我使用RoutedUICommand Requery声明了一个RoutedUICommand Requery类,然后使用了Window.CommandBindings

    

MenuItem的XAML现在看起来像:

      

事件处理程序如下所示:

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

但是调试器显示相同的运行时错误: 对象引用未设置为对象的实例。

我的两种方法都缺少什么?

我应该如何在WPF上下文菜单项单击事件处理程序中引用右键单击的对象?

注意CommandParameter

        

并在处理程序中使用它来确定它是哪个Grid

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

更新:
如果您希望menuitem处理程序转到Grid的子节点而不是Grid本身,请使用此方法

               

只需将TextBlocks替换为您的自定义对象类型即可。 然后在事件处理程序中,将Grid g = cm.PlacementTarget as Grid替换Grid g = cm.PlacementTarget as Grid ,将TextBlock t = cm.PlacementTarget as TextBlock (或任何自定义对象类型)。

通过在xaml中绑定数据上下文:

 ContextMenu DataContext="{Binding PlacementTarget.DataContext, RelativeSource= {RelativeSource Self}}"> 

然后你可以这样做:

 private void Context_MenuClick(object sender, RoutedEventArgs e) { var menuItem = e.Source as MenuItem; MyDoStuffFunction(menuItem.DataContext); } 

数据上下文将绑定到单击以打开ContextMenu的对象。

我从这个链接的代码项目文章中得到了它:

http://www.codeproject.com/Articles/162784/WPF-ContextMenu-Strikes-Again-DataContext-Not-Upda

menu = sender as MenuItem如果发件人不是MenuItem或其派生类menu = sender as MenuItem将为null。 随后试图取消引用菜单会爆炸。

您的发件人可能是Menu或ContextMenu或ToolStripMenuItem或其他forms的菜单项,而不是具体的MenuItem对象。 使用调试器断点在此处停止代码并检查发送方对象以确切地查看它是什么类。

对于RoutedEventArgs

  • RoutedEventArgs.source是引发事件的对象的引用
  • RoutedEventArgs.originalSource是在由父类进行任何可能的源调整之前由纯命中测试确定的报告源。

所以.Sender应该是答案。 但这取决于菜单项的添加和绑定方式

查看此答案集并选择适合您情况的方法!

你不应该检查RoutedEventArgs.Source而不是sender吗?

你有两个不同的问题。 这两个问题都导致了相同的exception,但在其他情况下无关:

第一个问题

在您的第一种方法中,您的代码是正确的并且运行良好,除了这里的问题:

 SCurrent.Status = MyCustControl.Status.Sixth; 

名称“Status”既可用作静态成员,也可用作实例成员。 我认为您将代码错误地剪切并粘贴到您的问题中。

可能还需要在MenuItem menu = sender as MenuItem;之后添加以下MenuItem menu = sender as MenuItem; ,根据您的具体情况:

  if(menu==null) return; 

第二个问题

在您的第二种方法中,您使用“发件人”而不是“e.Source”。 以下代码按预期工作:

 private void RequeryCommand_Executed(object sender, ExecutedRoutedEventArgs e) { IInputElement parent = (IInputElement)LogicalTreeHelper.GetParent((DependencyObject)e.Source); // Changed "sender" to "e.Source" in the line above MyCustControl SCurrent = new MyCustControl(); SCurrent = (MuCustControl)parent; string str = SCurrent.Name.ToString();// Error gone MessageBox.Show(str); } 

最后的说明

注意:如果使用命令方法,则没有理由将CommandParameter绑定到此。 它明显变慢并且需要更多代码。 e.Source将始终是源对象,因此不需要使用CommandParameter ,因此请使用它。

这对我有用: –

XAML: –

    

添加菜单项: –

 foreach (String s in columnNames) { var item = new MenuItem { IsCheckable = true, IsChecked = true ,Header=s}; AddColumnsContextMenu.Items.Add(item); } 

听众来了: –

 private void AddColumnsContextMenu_Click(object sender, RoutedEventArgs e) { MenuItem mi = e.Source as MenuItem; string title = mi.Header.ToString(); MessageBox.Show("Selected"+title); } 

谢谢…

在我的情况下,我能够使用:

 private void MenuItem_Click(object sender, RoutedEventArgs e) { MenuItem menuItem = e.Source as MenuItem; ContextMenu parent = menuItem.Parent as ContextMenu; ListBoxItem selectedItem = parent.PlacementTarget as ListBoxItem; }