3

TreeViewHierarchicalDataTemplate。我TreeViewContextMenu

<TreeView Name="_packageTreeView" ItemsSource="{Binding PackageExtendedList}" Behaviors:TreeViewInPlaceEditBehavior.IsEditable="True">
    <TreeView.ContextMenu>
        <ContextMenu StaysOpen="true">
            <MenuItem Header="Добавить пакет" Height="20" Command="{Binding AddPackageCommand}" 
                CommandParameter="{Binding ElementName=_packageTreeView, Path=SelectedItem}">
                    <MenuItem.Icon>
                        <Image Source="/Resources/ManualAdd.png" Width="15" Height="15"></Image>
                    </MenuItem.Icon>
            </MenuItem>
        </ContextMenu>
   </TreeView.ContextMenu>
   <TreeView.ItemTemplate>
       <HierarchicalDataTemplate ItemsSource="{Binding Childs}">bla bla bla</HierarchicalDataTemplate>
   </TreeView.ItemTemplate>
</TreeView>

如您所见,我绑定Command到菜单项。像往常一样在 ViewModell 类中定义的 AddPackageCommand。调用命令工作正常,但我总是nullCommandParameter. 我发现了一些类似于我的问题,但我不明白解决方案。例如:

WPF 中 ContextMenu 中的 CommandParameters

无论如何它对我不起作用:(我做错了什么?

更新

这似乎有效,但都是一样的,我不明白为什么CommandParameter不能使用TreeView.Name.

CommandParameter="{Binding PlacementTarget, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ContextMenu}}}"

例如,这样的示例可以正常工作

<i:EventTrigger EventName="SelectedItemChanged">
    <i:InvokeCommandAction Command="{Binding PackageTreeItemChangeCommand}" CommandParameter="{Binding ElementName=_packageTreeView, Path=SelectedItem}"/>
</i:EventTrigger>

什么鬼……

无论如何,我有TreeView对象 in CommandParameter,而不是TreeViewItem。我可以SelectedItem从那里得到TreeView,但我怎样才能发送完全TreeViewItem一样CommandParameter

到谢里登

问题是为什么这不起作用。

CommandParameter="{Binding ElementName=_packageTreeView, Path=SelectedItem}"

这有效

CommandParameter="{Binding PlacementTarget, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ContextMenu}}}"

为什么有时我可以直接使用 TreeView 控件名称,有时却不能。据我了解,物质是不同的 DataContextTreeView控制,ContextMenu因为ContextMenu它有自己的 VisualTree,它不是TreeView ViaualTree.

不幸的是,这种方法也不起作用,我null又遇到了。当然,我设置了 TreeView.Tag。

<ContextMenu DataContext="{Binding PlacementTarget.Tag, RelativeSource={
            RelativeSource Self}}" StaysOpen="true">
    <MenuItem Header="Добавить пакет" Height="20" Command="{Binding AddPackageCommand}" 
                CommandParameter="{Binding ElementName=_packageTreeView, Path=SelectedItem}">
        <MenuItem.Icon>
             <Image Source="/Resources/ManualAdd.png" Width="15" Height="15"></Image>
        </MenuItem.Icon>
    </MenuItem>
</ContextMenu>

这是最简单的方法,但是如果我在 ViewModel 中有 SelectedItem 属性,则将其绑定到 是没有意义的CommandParameter,因为我已经在 ViewModel 中有它。

 <MenuItem Header="Добавить пакет" Height="20" Command="{Binding AddPackageCommand}" 
    CommandParameter="{Binding SelectedItem}">
    <MenuItem.Icon>
        <Image Source="/Resources/ManualAdd.png" Width="15" Height="15"></Image>
    </MenuItem.Icon>
</MenuItem>
4

1 回答 1

2

您向我们展示了您已经有了答案……您到底为什么要就同一主题发布另一个问题,而不是简单地按照答案中的示例进行操作?它对您不起作用,因为您没有正确复制答案。

在您的示例帖子答案中,该Tag属性设置TreeView为应用菜单的控件,但您还没有这样做。

您的下一个问题是您Tag在...中再次忽略了此属性CommandParameter,您已从正确答案中更改了此属性:

CommandParameter="{Binding PlacementTarget.Tag, RelativeSource={RelativeSource 
    FindAncestor, AncestorType={x:Type ContextMenu}}}

在您的问题中对此:

CommandParameter="{Binding PlacementTarget, RelativeSource={RelativeSource 
    FindAncestor, AncestorType={x:Type ContextMenu}}}"

您需要做的就是复制并粘贴它。尽管如此,您可能会更幸运地这样做:

<TreeView Tag="{Binding DataContext, RelativeSource={RelativeSource Self}}" 
    Name="_packageTreeView" ItemsSource="{Binding PackageExtendedList}" 
    Behaviors:TreeViewInPlaceEditBehavior.IsEditable="True">
    <TreeView.ContextMenu>
        <ContextMenu DataContext="{Binding PlacementTarget.Tag, RelativeSource={
            RelativeSource Self}}" StaysOpen="true">
            <MenuItem Header="Добавить пакет" Height="20" Command="{Binding AddPackageCommand}" 
                CommandParameter="{Binding ElementName=_packageTreeView, Path=SelectedItem}">
                    <MenuItem.Icon>
                        <Image Source="/Resources/ManualAdd.png" Width="15" Height="15"></Image>
                    </MenuItem.Icon>
            </MenuItem>
        </ContextMenu>
   </TreeView.ContextMenu>
   <TreeView.ItemTemplate>
       <HierarchicalDataTemplate ItemsSource="{Binding Childs}">bla bla bla</HierarchicalDataTemplate>
   </TreeView.ItemTemplate>
</TreeView>

查看TreeView.Tag属性... this 设置为 its own DataContext,这意味着设置为 theDataContext的任何TreeView内容现在都可以在Tag属性对象中使用。

接下来,查看ContextMenu.DataContext属性... this 设置为 的Tag属性PlacementTarget,这是ContextMenu应用 的控件,或者在本例中为Treeview.

如果您还没有解决,这意味着DataContextContextMenu被设置为与 的 相同的DataContext对象TreeView。如果这不是您想要的,因为您Command在不同的对象上,那么只需更改属性中的Binding路径Tag以指向具有该对象的任何Command位置。

为了使这更简单,您可以做的最后一件事是在绑定到该属性的视图模型/代码中添加一个TreeView.SelectedItem属性:

<TreeView SelectedItem="{Binding SelectedItem}"... />

然后,您可以简单地为您的 参考此属性CommandParameter

<MenuItem Header="Добавить пакет" Height="20" Command="{Binding AddPackageCommand}" 
    CommandParameter="{Binding SelectedItem}">
    <MenuItem.Icon>
        <Image Source="/Resources/ManualAdd.png" Width="15" Height="15"></Image>
    </MenuItem.Icon>
</MenuItem>

最后一部分当然假设您已将视图模型/代码设置TagTreeView. 如果您仍然不理解这一点,请查看WPF Tutorial.NET 上的 WPF 中的上下文菜单页面。

更新>>>

我只是不明白你为什么发布这个问题。首先,您说您无法做某事,但随后在另一篇文章中为我们提供了指向有效解决方案的链接。在尝试帮助您之后,您然后说它确实有效,但您不知道为什么......但是您再次正确回答了自己的问题:

据我了解,问题是TreeView控件和ContextMenu的DataContext不同,因为ContextMenu有自己的VisualTree,它不是TreeView ViaualTree的一部分。

正如你所说,它ContextMenu有自己的视觉树。这意味着它不知道另一个可视树中的控件,无论是命名的还是其他的。但是,如果ContextMenu.DataContext提供了一个对象,例如包含视图,那么它可以知道另一个可视化树中的控件(更具体地说,是视图中控件的可视化树)。

整个问题似乎归结为您对Binding一般情况和Binding.Path更具体的语法缺乏了解。请查看 MSDN 上的以下文章以获取有关此主题的更多帮助:

Binding.Path 属性

属性路径语法

相对源标记扩展

很多人在会走路之前就尝试使用 WPF 跑步。

于 2013-10-02T09:59:38.523 回答