1

I have the following Layout:

public class ParentUserControl : UserControl{...}

<ParentNameSpace:ParentUserControl
...
DataContext={Binding MyViewModel ....}
>
<TreeView ...>                
<HierarchicalDataTemplate    
         .... >
                <StackPanel>
                    <StackPanel.ContextMenu>
                        <ContextMenu>
                            <MenuItem Header="item" 
                            Command="{Binding DataContext.SomeCommandInMyViewModel,
                                RelativeSource={RelativeSource  
                                AncestorType={x:Type ParentUserControl}}}"/>
                        </ContextMenu>
                    </StackPanel.ContextMenu>
                    <TextBlock Text="{Binding Path=Name}"/>
                </StackPanel>
            </HierarchicalDataTemplate>
</TreeView>

Im trying to call a command of the UserControls ViewModel from within the Context of a TreeViewItem with no success. It tells me ParentUserControl Is not supported in a wpf Project. If I change AncestorType to UserControl the Command does not get called. Is there something I miss?

H.B.
  • 166,899
  • 29
  • 327
  • 400
Milleu
  • 139
  • 1
  • 12

1 Answers1

1

This is because ContextMenu is not a part of the visual tree. The simplest way without changing code-behind is this:

Give a name to ParentUserControl:

<ParentNameSpace:ParentUserControl x:Name="ParentRoot" ... >

Use this binding:

Command="{Binding Source={x:Reference Name=ParentRoot}, Path=DataContext.SomeCommandInMyViewModel}"

Update for using without x:Name attribute.

You can use ContextMenu.PlacementTarget property, which will point to StackPanel in your case. Then you can use it's Tag property for accessing your view-model.

<StackPanel Tag="{Binding RelativeSource={RelativeSource AncestorType=ParentNameSpace:ParentUserControl}, Path=DataContext}">

And command:

Command="{Binding RelativeSource={RelativeSource AncestorType=ContextMenu}, Path=PlacementTarget.Tag.SomeCommandInMyViewModel}"
Sam
  • 1,384
  • 2
  • 20
  • 30
  • My base class is abstract and derives from another abstract class with a single Parameter constructor which causes: The type 'ParentUserControl ' cannot have a Name attribute. Value types and types without a default constructor can be used as items within a ResourceDictionary. I dont want to change the Base classes do you have another idea to resolve this :/? – Milleu Sep 21 '16 at 14:44
  • awesome thanks!, it works!! :) for my understanding - I couldnt use the Ancestor within the ContextMenu because its in a different visual tree (different process or something?) - so I have to define the Tag (or name) to access the ViewModel. I have a couple more HierachicalDataTemplates can I define the Tag once in Treeview or does the Tag always need to defined in the owners element ?(had no success moving the Tag to Treeview and change AncestorType to TreeView) – Milleu Sep 21 '16 at 15:37
  • Yes, you can think about it like it is just separate visual tree which contains only `ContextMenu` (the same true for `Popup`). To resolve this barrier, there is [`ContextMenu.PlacementTarget`](https://msdn.microsoft.com/library/system.windows.controls.contextmenu.placementtarget(v=vs.110).aspx) which points to element in which your `ContextMenu` placed. This is `StackPanel` in your case, so you'll have to deal with it anyway. You are also have other ways, look at [this](http://stackoverflow.com/questions/1013558/elementname-binding-from-menuitem-in-contextmenu) question and related section. – Sam Sep 22 '16 at 08:15