如何在 WPF 上下文菜单项单击事件处理程序中引用右键单击的对象? [英] How to reference right-clicked object in WPF Context Menu item click event handler?

查看:14
本文介绍了如何在 WPF 上下文菜单项单击事件处理程序中引用右键单击的对象?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

 <Grid.ContextMenu><上下文菜单><MenuItem Name="EditStatusCm" Header="更改状态" Click="EditStatusCm_Click"/></上下文菜单></Grid.ContextMenu>

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

 private void EditStatusCm_Click(object sender, RoutedEventArgs e){MyCustControl SCurrent = new MyCustControl();MenuItem menu = 作为 MenuItem 的发件人;SCurrent = menu.DataContext as MyCustControl;//这里我得到一个运行时错误SCurrent.Status = MyCustControl.Status.Sixth;}

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

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

已编辑(添加):

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

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

<Window.CommandBindings><CommandBinding Command="MyNamespace:DataCommands.Requery" Executed="RequeryCommand_Executed"></CommandBinding></Window.CommandBindings>

MenuItem 的 XAML 现在看起来像:

<Grid.ContextMenu><上下文菜单><MenuItem Name="EditStatusCm" Header="更改状态" Command="MyNamespace:DataCommands.Requery"/></上下文菜单></Grid.ContextMenu>

事件处理程序看起来像:

 private void RequeryCommand_Executed(object sender, ExecutedRoutedEventArgs e){IInputElement parent = (IInputElement)LogicalTreeHelper.GetParent((DependencyObject)sender);MyCustControl SCurrent = new MyCustControl();SCurrent = (MuCustControl) 父级;string str = SCurrent.Name.ToString();//这里我得到同样的错误消息框.Show(str);}

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

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

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

解决方案

注意CommandParameter

<网格背景=红色"高度=100"宽度=100"><Grid.ContextMenu><上下文菜单><菜单项标头="更改状态"点击="EditStatusCm_Click"CommandParameter="{Binding RelativeSource={RelativeSource Self}, Path=Parent}"/></上下文菜单></Grid.ContextMenu></网格>

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

 private void EditStatusCm_Click(object sender, RoutedEventArgs e){MenuItem mi = 作为 MenuItem 的发件人;如果(mi!= null){ContextMenu cm = mi.CommandParameter as ContextMenu;如果(厘米!= 空){网格 g = cm.PlacementTarget 作为网格;如果 (g != null){Console.WriteLine(g.Background);//将打印红色}}}}

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

<网格背景=红色"高度=100"宽度=100"><网格.资源><ContextMenu x:Key="TextBlockContextMenu"><菜单项标头="更改状态"点击="EditStatusCm_Click"CommandParameter="{Binding RelativeSource={RelativeSource Self}, Path=Parent}"/></上下文菜单><Style TargetType="{x:Type TextBlock}"><Setter Property="ContextMenu" Value="{StaticResource TextBlockContextMenu}"/></风格></Grid.Resources><Grid.RowDefinitions><行定义/><行定义/></Grid.RowDefinitions><TextBlock 文本="Row0" Grid.Row="0"/><TextBlock 文本="Row1" Grid.Row="1"/></网格>

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

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?

解决方案

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

这篇关于如何在 WPF 上下文菜单项单击事件处理程序中引用右键单击的对象?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆