在WPF中的整个TreeViewItem行上显示上下文菜单

在WPF中的整个TreeViewItem行上显示上下文菜单,wpf,xaml,templates,contextmenu,treeviewitem,Wpf,Xaml,Templates,Contextmenu,Treeviewitem,我有一个具有异构节点类型的树视图。使用HierarchycalDataTemplate在XAML中配置每个节点类型 某些节点具有上下文菜单,这取决于节点的类型。ContextMenus在XAML中定义为静态资源,并附加到HierarchycalDataTemplate中的DockPanel 此外,我正在为bendewey在下面的StackOverflow问题中描述的TreeView项目使用ControlTemplate。此ControlTemplate的定义是为了在选中时高亮显示完整的TreeV

我有一个具有异构节点类型的树视图。使用HierarchycalDataTemplate在XAML中配置每个节点类型

某些节点具有上下文菜单,这取决于节点的类型。ContextMenus在XAML中定义为静态资源,并附加到HierarchycalDataTemplate中的DockPanel

此外,我正在为bendewey在下面的StackOverflow问题中描述的TreeView项目使用ControlTemplate。此ControlTemplate的定义是为了在选中时高亮显示完整的TreeViewItem。 在该行的任何部分上单击鼠标左键,即可选择该项目

相反,在HierarchycalDataTemplate中定义的上下文菜单仅在行的右侧部分起作用

我正在寻找一种方法来配置ContextMenus,以便它们也可以在完整的行中使用

这似乎需要将上下文菜单附加到ControlTemplate中的元素,并将TemplateBinding绑定到HierarchycalDataTemplate中定义的内容,但我不知道如何执行此操作


顺便说一句,VisualStudio中的解决方案资源管理器正好具有这种行为。上下文菜单取决于节点类型,在完整项上可用,包括展开/折叠按钮的左侧。

编辑您需要以树状项样式删除网格的两列:

请注意,您应调整转换器,以考虑所需的额外裕度:

public class LeftMarginMultiplierConverter : IValueConverter
{
    public double Length { get; set; } 

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        var item = value as TreeViewItem;
        if (item == null)
            return new Thickness(0);
        int extra = int.Parse(parameter.ToString());
        var t = item.GetDepth();
        return new Thickness(Length * (item.GetDepth() + extra), 0, 0, 0);
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new System.NotImplementedException();
    }
}
如果converter参数为1,它将向项目的深度添加一个点。我用它作为标题部分


另一种方法可能是向TreeViewItem样式的ContentPresenter添加数据模板。虽然我不知道如何绑定ContextMenu,但我更喜欢这个

这不是问题所在。TreeViewItem的ControlTemplate根据树的深度定义边距,然后是展开/折叠按钮,然后是数据模板所在的ContentPresenter。我希望整行都有上下文菜单,因此它需要在ControlTemplate中的边框、网格或某些新元素上定义,但要绑定到HierarchycalDataTemplate中的定义。谢谢,这很有效。对于将缩进的责任向下转移到DataTemplates和HierarchycalDataTemplates中,我有一点不好的感觉。我的直觉反应是它不属于那里。但是,您可能会争辩说ContextMenu也不属于该行的这一部分。
<TreeView Margin="50" HorizontalContentAlignment="Stretch" DataContext="{Binding}" ItemsSource="{Binding Models}">
    <TreeView.ItemTemplate>
        <HierarchicalDataTemplate DataType="{x:Type local:Model}" ItemsSource="{Binding Models}">
            <Border Background="Transparent">
                <TextBlock Margin="{Binding  Converter={StaticResource lengthConverter}, ConverterParameter=1,
                                                                 RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=TreeViewItem}}" 
                           Text="{Binding Name}" />
                <Border.ContextMenu>
                    <ContextMenu>
                        <MenuItem Header="dddd"/>
                    </ContextMenu>
                </Border.ContextMenu>
            </Border>
        </HierarchicalDataTemplate>
    </TreeView.ItemTemplate>
</TreeView>
public class LeftMarginMultiplierConverter : IValueConverter
{
    public double Length { get; set; } 

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        var item = value as TreeViewItem;
        if (item == null)
            return new Thickness(0);
        int extra = int.Parse(parameter.ToString());
        var t = item.GetDepth();
        return new Thickness(Length * (item.GetDepth() + extra), 0, 0, 0);
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new System.NotImplementedException();
    }
}