Wpf MVVM样式的TreeView元素上的ContextMenu

Wpf MVVM样式的TreeView元素上的ContextMenu,wpf,mvvm,contextmenu,datacontext,Wpf,Mvvm,Contextmenu,Datacontext,我有一个“简单”的任务,在树视图(元素)上有一个上下文菜单,它是以MVVM的方式完成的。 搜索网页时,我找到了一些解决方案,我可以使用按钮等,但不能使用TreeView。我认为问题在于设置TreeView的ItemsSource属性,该属性为每个项目提供自己的DataContext 下面是我的小测试应用程序,您可以看到button的工作原理,但TreeView元素不适用: MainWindow.xaml: <Window x:Class="ContextMenu.MainWindow"

我有一个“简单”的任务,在树视图(元素)上有一个上下文菜单,它是以MVVM的方式完成的。 搜索网页时,我找到了一些解决方案,我可以使用按钮等,但不能使用TreeView。我认为问题在于设置TreeView的ItemsSource属性,该属性为每个项目提供自己的DataContext

下面是我的小测试应用程序,您可以看到button的工作原理,但TreeView元素不适用:

MainWindow.xaml:

<Window x:Class="ContextMenu.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">

    <Grid >
        <StackPanel>
            <TextBlock Text="{Binding MyText}" />

            <Button Tag="{Binding DataContext,RelativeSource={RelativeSource Mode=Self}}" Content="Click me">
                <Button.ContextMenu>
                    <ContextMenu>
                        <MenuItem Header="{Binding PlacementTarget.Tag.MyText,
                            RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=ContextMenu}}" />
                    </ContextMenu>
                </Button.ContextMenu>
            </Button>

            <TreeView ItemsSource="{Binding MyList}" Tag="{Binding DataContext, RelativeSource={RelativeSource Mode=Self}}">
                <TreeView.ItemTemplate>
                    <HierarchicalDataTemplate>
                        <TextBlock Text="{Binding Name}">
                            <TextBlock.ContextMenu>
                                <ContextMenu>
                                    <MenuItem Header="{Binding Path=PlacementTarget.Tag.MyText, 
                                        RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ContextMenu}}" />
                                </ContextMenu>
                            </TextBlock.ContextMenu>
                        </TextBlock>
                    </HierarchicalDataTemplate>
                </TreeView.ItemTemplate>         
            </TreeView>

        </StackPanel>        
    </Grid>
</Window>
public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        DataContext = new MainWindowVM();
    }
}
public class MainWindowVM
{
    public string MyText { get; set; }
    public ObservableCollection<TreeElement> MyList { get; set; }

    public MainWindowVM()
    {
        MyText = "This is my Text!";
        MyList = new ObservableCollection<TreeElement>();
        MyList.Add(new TreeElement("String 1"));
        MyList.Add(new TreeElement("String 2"));
    }
}

public class TreeElement
{
    public string Name { get; set; }
    public TreeElement(string Name)
    {
        this.Name = Name;
    }
}
MainWindowVM.cs:

<Window x:Class="ContextMenu.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">

    <Grid >
        <StackPanel>
            <TextBlock Text="{Binding MyText}" />

            <Button Tag="{Binding DataContext,RelativeSource={RelativeSource Mode=Self}}" Content="Click me">
                <Button.ContextMenu>
                    <ContextMenu>
                        <MenuItem Header="{Binding PlacementTarget.Tag.MyText,
                            RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=ContextMenu}}" />
                    </ContextMenu>
                </Button.ContextMenu>
            </Button>

            <TreeView ItemsSource="{Binding MyList}" Tag="{Binding DataContext, RelativeSource={RelativeSource Mode=Self}}">
                <TreeView.ItemTemplate>
                    <HierarchicalDataTemplate>
                        <TextBlock Text="{Binding Name}">
                            <TextBlock.ContextMenu>
                                <ContextMenu>
                                    <MenuItem Header="{Binding Path=PlacementTarget.Tag.MyText, 
                                        RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ContextMenu}}" />
                                </ContextMenu>
                            </TextBlock.ContextMenu>
                        </TextBlock>
                    </HierarchicalDataTemplate>
                </TreeView.ItemTemplate>         
            </TreeView>

        </StackPanel>        
    </Grid>
</Window>
public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        DataContext = new MainWindowVM();
    }
}
public class MainWindowVM
{
    public string MyText { get; set; }
    public ObservableCollection<TreeElement> MyList { get; set; }

    public MainWindowVM()
    {
        MyText = "This is my Text!";
        MyList = new ObservableCollection<TreeElement>();
        MyList.Add(new TreeElement("String 1"));
        MyList.Add(new TreeElement("String 2"));
    }
}

public class TreeElement
{
    public string Name { get; set; }
    public TreeElement(string Name)
    {
        this.Name = Name;
    }
}
公共类MainWindowVM
{
公共字符串MyText{get;set;}
公共ObservableCollection MyList{get;set;}
公共MainWindowVM()
{
MyText=“这是我的文本!”;
MyList=新的ObservableCollection();
添加(新的树元素(“字符串1”);
添加(新的树元素(“字符串2”));
}
}
公共类树元素
{
公共字符串名称{get;set;}
公共树元素(字符串名称)
{
this.Name=Name;
}
}
谢谢你的帮助!! 约尔格

你很接近

你在做什么:

  • 您可以将
    TreeView
    标记设置为自己的
    DataContext
    。这是 不必要
  • 您尝试从
    上下文菜单.PlacementTarget
    获取
    Tag.MyText
    ——即
    TextBlock
    TextBlock
    没有设置
    标记
  • 你应该做什么:

  • 文本块的
    标记设置为窗口的
    DataContext
    (窗口是
    TextBlock
    祖先,您应该通过
    relativesourcemode=FindAncestor
  • 第二部分还可以-在第一步中设置了
    TextBlock.Tag

  • 谢谢你的帮助。我对placementtargets和tags没有“全面的了解”。。。在你的回答之后,很清楚:)