WPF 树视图上下文菜单命令参数

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/19133654/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-13 09:46:22  来源:igfitidea点击:

WPF treeview contextmenu command parameter

wpftreeviewcontextmenucommandparameter

提问by monstr

I have TreeViewwith HierarchicalDataTemplate. On TreeViewI have ContextMenu

TreeViewHierarchicalDataTemplate。在TreeView我有ContextMenu

<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>

As you can see, I bind Commandto menu item. AddPackageCommand defined in ViewModell class as usually. Invoke command works fine, but I always have nullin CommandParameter. I found some questions similar to my, but I don't understand solutions. For example:

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

CommandParameters in ContextMenu in WPF

WPF 中 ContextMenu 中的 CommandParameters

Anyway it doesn't work for me :( What am I doing wrong?

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

Updated

更新

That seems to be working, but it's all the same, I don't understand why CommandParameterdoesn't work with TreeView.Name.

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

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

for examplle, such a sample works fine

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

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

What's the hell...

什么鬼...

And anyway, I have TreeViewobject in CommandParameter, not TreeViewItem. I can get SelectedItemfrom TreeView, but how can I send exactly TreeViewItemas CommandParameter?

无论如何,我在 中有TreeView对象CommandParameter,而不是TreeViewItem。我可以SelectedItemTreeView,但我怎么能发送准确TreeViewItemCommandParameter

to Sheridan

到谢里登

Question was WHYthis doesn't work.

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

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

And this works

这有效

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

WHYsometimes I can use direct TreeView control name and sometimes I cannot. As I understand, matter is different DataContext of TreeViewcontrol and ContextMenubecause ContextMenuhas its own VisualTree and it is not the part of TreeViewViaualTree.

为什么有时我可以使用直接的 TreeView 控件名称,有时我不能。据我了解,问题是不同的TreeView控制数据上下文,ContextMenu因为ContextMenu它有自己的 VisualTree 而不是TreeViewViaualTree.

Unfortunately, that approach doesn't worktoo, I have nullagain. I set TreeView.Tag, sure.

不幸的是,这种方法也行不通,我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>

This is the easiest way, but if I have SelectedItem property in ViewModel it has no sense bind it to CommandParameter, because I already have it in ViewModel.

这是最简单的方法,但如果我在 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>

回答by Sheridan

You showed us that you already have an answer... why on earth did you post yet another question on this same subject instead of simply following the example in the answer? It doesn't work for you, because you didn't copy the answer properly.

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

In your example post answer, the Tagproperty is set to the TreeViewcontrol that the menu is applied on, but you haven't done this.

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

Your next problem is that you have ignored this Tagproperty again in the CommandParameter... somehow, you have changed this from the correct answer:

你的下一个问题是你Tag再次忽略了这个属性CommandParameter......不知何故,你已经改变了正确答案:

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

to this in your question:

在你的问题中对此:

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

All you needed to do was copy and paste it. All the same, you might have even more luck doing this:

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

<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>

Look at the TreeView.Tagproperty... this is set to its own DataContext, which means that whatever is set as the DataContextof the TreeViewis now available in the Tagproperty object.

TreeView.Tag属性......这是设置为自己的DataContext,这意味着,无论设置为DataContextTreeView是现在在可用的Tag属性对象。

Next, look at the ContextMenu.DataContextproperty... this is set to the Tagproperty of the PlacementTarget, which is the control that the ContextMenuis applied to, or in this case, the Treeview.

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

If you haven't worked it out yet, this means that the DataContextof the ContextMenuis now set to the same object as the DataContextof the TreeView. If this is not what you want because your Commandis on a different object, then just change the Bindingpath in the Tagproperty to point to wherever the object that had the Commandis.

如果你还没有制定出来呢,这意味着DataContextContextMenu是现在设置为相同的对象DataContextTreeView。如果这不是您想要的,因为您Command在不同的对象上,那么只需更改属性中的Binding路径Tag以指向具有该对象的任何Command位置。

The last thing that you can do to make this simpler is to add a property to your view model/code behind that binds to the TreeView.SelectedItemproperty:

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

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

Then you can simply refer to this property for your CommandParameter:

然后你可以简单地为你的这个属性引用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>

This last part of course assumes that you have set your view model/code behind as the Tagproperty of the TreeView. If you still don't understand this, take a look at the Context Menus in WPFpage on WPF Tutorial.NET.

当然,这最后一部分假定您已经设置您的视图模型/代码背后的Tag财产TreeView。如果您仍然不明白这一点,请查看WPF Tutorial.NET 上的 WPF 页面中的上下文菜单

UPDATE >>>

更新 >>>

I simply don't understand why you posted this question. First you said you couldn't do something, but then provided us with a link to a valid solution in another post. After trying to help you, you then say that it did work, but you don't know why... but then you correctly answered your own question again:

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

As I understand, matter is different DataContext of TreeView control and ContextMenu because ContextMenu has its own VisualTree and it is not the part of TreeView ViaualTree.

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

As you said, the ContextMenuhas its own visual tree. This means that it is not aware of controls, named or otherwise, in another visual tree. However, if the ContextMenu.DataContextis provided with an object such as the containing view, then it canbe aware of controls in another visual tree (more specifically, the visual tree of the controls in the view).

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

This whole issue seems to be down to a lack of knowledge on your part about Bindingin general and Binding.Pathsyntax more specifically. Please take a look at the following articles on MSDN for more help on this topic:

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

Binding.Path Property

Binding.Path 属性

Property Path Syntax

属性路径语法

RelativeSource MarkupExtension

相对源标记扩展

So many people try to run with WPF before they can walk.

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