rem*_*rem 10 c# wpf contextmenu event-handling
在WPF应用程序中,有一个Grid包含许多对象(它们来自自定义控件).我想使用上下文菜单对每个操作执行一些操作:
<Grid.ContextMenu>
<ContextMenu>
<MenuItem Name="EditStatusCm" Header="Change status" Click="EditStatusCm_Click"/>
</ContextMenu>
</Grid.ContextMenu>
Run Code Online (Sandbox Code Playgroud)
但是在事件处理程序中,我无法知道哪些对象被右键单击:
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;
}
Run Code Online (Sandbox Code Playgroud)
在该注释行上调试器说:对象引用未设置为对象的实例.
请帮忙,我的代码有什么问题?
编辑(补充):
我尝试使用Command方法做同样的事情:
我宣布了一个DataCommands类,RoutedUICommand Requery然后使用Window.CommandBindings
<Window.CommandBindings>
<CommandBinding Command="MyNamespace:DataCommands.Requery" Executed="RequeryCommand_Executed"></CommandBinding>
</Window.CommandBindings>
Run Code Online (Sandbox Code Playgroud)
MenuItem的XAML现在看起来像:
<Grid.ContextMenu>
<ContextMenu>
<MenuItem Name="EditStatusCm" Header="Change status" Command="MyNamespace:DataCommands.Requery"/>
</ContextMenu>
</Grid.ContextMenu>
Run Code Online (Sandbox Code Playgroud)
事件处理程序如下所示:
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);
}
Run Code Online (Sandbox Code Playgroud)
但是调试器显示相同的运行时错误:对象引用未设置为对象的实例.
我的两种方法都缺少什么?
如何在WPF上下文菜单项单击事件处理程序中引用右键单击的对象?
ken*_*ner 25
注意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>
Run Code Online (Sandbox Code Playgroud)
并在处理程序中使用它来确定它是哪个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
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
更新:
如果您希望menuitem处理程序转到Grid的子节点而不是Grid本身,请使用此方法
<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>
Run Code Online (Sandbox Code Playgroud)
只需将TextBlocks替换为您的自定义对象类型即可.然后在事件处理程序中,替换Grid g = cm.PlacementTarget as Grid为TextBlock t = cm.PlacementTarget as TextBlock(或任何您的自定义对象类型).
通过在xaml中绑定数据上下文:
ContextMenu DataContext="{Binding PlacementTarget.DataContext, RelativeSource= {RelativeSource Self}}">
Run Code Online (Sandbox Code Playgroud)
然后你可以这样做:
private void Context_MenuClick(object sender, RoutedEventArgs e)
{
var menuItem = e.Source as MenuItem;
MyDoStuffFunction(menuItem.DataContext);
}
Run Code Online (Sandbox Code Playgroud)
数据上下文将绑定到单击的对象以打开ContextMenu.
我从这个链接的codeproject文章中得到了它:
http://www.codeproject.com/Articles/162784/WPF-ContextMenu-Strikes-Again-DataContext-Not-Upda