ContextMenu的Item如何绑定命令

发布于:2025-07-12 ⋅ 阅读:(18) ⋅ 点赞:(0)
<UserControl x:Class="ATE.View.需求管理View"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:ATE.View"
             xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
             xmlns:vm="clr-namespace:ATE.VM"
             mc:Ignorable="d"
             FontFamily="Microsoft YaHei"
             x:Name="root"
             d:DesignHeight="450" d:DesignWidth="800">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="auto" />
            <ColumnDefinition Width="5*" />
        </Grid.ColumnDefinitions>

        <GroupBox Grid.Column="0"
                  Margin="10"
                  Header="本地数据">
            <TreeView ItemsSource="{Binding RootNodes}"
                      Tag="{Binding DataContext, ElementName=root}"
                      x:Name="treeView">
                <TreeView.Resources>
                    <!-- 组节点模板 -->
                    <HierarchicalDataTemplate DataType="{x:Type vm:GroupNode}"
                                              ItemsSource="{Binding Children}">
                        <StackPanel Orientation="Horizontal"
                                    x:Name="stackPanel"
                                    >
                            <Image Source="{Binding Icon}"
                                   Width="16"
                                   Height="16" />
                            <TextBlock Text="{Binding Name}"
                                       Margin="5,0" />
                            <StackPanel.ContextMenu>
                                <ContextMenu DataContext="{Binding PlacementTarget.Tag, RelativeSource={RelativeSource Self}}">
                                    <MenuItem Header="添加分组"
                                              Command="{Binding AddGroupCommand}"
                                              CommandParameter="{Binding RelativeSource={RelativeSource 
                                                    Mode=FindAncestor,AncestorType=ContextMenu},
                                                    Path=PlacementTarget.DataContext}" />
                                    <MenuItem Header="添加元素"
                                              Command="{Binding AddElementCommand}"
                                              CommandParameter="{Binding RelativeSource={RelativeSource 
                                                    Mode=FindAncestor,AncestorType=ContextMenu},
                                                    Path=PlacementTarget.DataContext}" />
                                    <Separator />
                                    <MenuItem Header="删除"
                                              Command="{Binding DeleteNodeCommand}"
                                              CommandParameter="{Binding RelativeSource={RelativeSource Mode=FindAncestor, 
                                                     AncestorType=ContextMenu}, 
                                                     Path=PlacementTarget.DataContext}" />
                                </ContextMenu>
                            </StackPanel.ContextMenu>
                        </StackPanel>
                    </HierarchicalDataTemplate>

                    <!-- 元素节点模板 -->
                    <DataTemplate DataType="{x:Type vm:ElementNode}">
                        <StackPanel Orientation="Horizontal"
                                    Tag="{Binding DataContext, ElementName=root}">
                            <Image Source="{Binding Icon}"
                                   Width="16"
                                   Height="16" />
                            <TextBlock Text="{Binding Name}"
                                       Margin="5,0"
                                       FontStyle="Italic" />
                            <StackPanel.ContextMenu>
                                <ContextMenu DataContext="{Binding PlacementTarget.Tag, RelativeSource={RelativeSource Self}}">
                                    <MenuItem Header="删除"
                                              Command="{Binding DeleteNodeCommand}"
                                              CommandParameter="{Binding RelativeSource={RelativeSource Mode=FindAncestor, 
                                                         AncestorType=ContextMenu}, 
                                                         Path=PlacementTarget.DataContext}" />  
                                </ContextMenu>
                            </StackPanel.ContextMenu>
                        </StackPanel>
                    </DataTemplate>
                </TreeView.Resources>
            </TreeView>
        </GroupBox>

    
    </Grid>
</UserControl>

首先要理解为什么不能直接绑定命令呢

正常情况,我们的控件都是在可视化树上,UserControl继承DataContext,一般都可以直接绑定,如果是一些定制化容器如ListBox,ItemsControl这种就需要用下面这种方法来绑定,但这些都是建立在控件在可视化树上

Command="{Binding RelativeSource={RelativeSource AncestorType=UserControl, Mode=FindAncestor}, Path=DataContext.EditUserCommand}" CommandParameter="{Binding}"

ContextMenu属于PopUp控件,不在可视化树上就不能用上述方法

如何绑定不在可视化树上的控件

用控件的tag来中转

上面那个例子,要绑定TreeView中的ContextMenu

首先要让ContextMenu的上层控件的tag来绑定UserControl的DataContext

<UserControl x:Class="ATE.View.需求管理View"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:ATE.View"
             xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
             xmlns:vm="clr-namespace:ATE.VM"
             mc:Ignorable="d"
             FontFamily="Microsoft YaHei"
             x:Name="root"
             d:DesignHeight="450" d:DesignWidth="800">
<StackPanel Orientation="Horizontal"
            x:Name="stackPanel"
            Tag="{Binding DataContext, ElementName=root}">

为什么一定要上层控件能,因为ContextMenu里面有一个属性PlacementTarget,他指向的就是上层空间,ContextMenuStackPanel包裹,所以指向StackPanel

<ContextMenu DataContext="{Binding PlacementTarget.Tag, RelativeSource={RelativeSource Self}}">
    <MenuItem Header="删除"
              Command="{Binding DeleteNodeCommand}"
              CommandParameter="{Binding RelativeSource={RelativeSource Mode=FindAncestor, 
                     AncestorType=ContextMenu}, 
                     Path=PlacementTarget.DataContext}" />  
</ContextMenu>

一定要用RelativeSource指向自己,如果不这样的话,Wpf会在可视化树中找PlacementTarget属性,很显然是找不到的,这样就可也绑定命令了,只有通过 PlacementTarget.DataContext,才能精确拿到你右键的那个节点。


网站公告

今日签到

点亮在社区的每一天
去签到