<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,他指向的就是上层空间,ContextMenu被StackPanel包裹,所以指向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,才能精确拿到你右键的那个节点。