7

I'm trying to bind MenuItem's Command to command contained in UserControl.DataContext. I've found couple of similar question, but solution according to them is failing to me:

<UserControl ...> <UserControl.Resources> <DataTemplate x:Key="TileItemStye"> <Grid Width="100" Height="100"> <Grid.ContextMenu> <ContextMenu> <MenuItem Header="Remove" Command="{Binding DataContext.RemoveItem, RelativeSource={RelativeSource FindAncestor, AncestorType=UserControl}}"> </MenuItem> </ContextMenu> </Grid.ContextMenu> </Grid> </DataTemplate> </UserControl.Resources> <Grid> <ListView ItemsSource="{Binding Path=Files}" ItemTemplate="{DynamicResource TileItemStye}" > <ListView.ItemsPanel> <ItemsPanelTemplate> <WrapPanel /> </ItemsPanelTemplate> </ListView.ItemsPanel> </ListView> </Grid> 

UserControl's DataContext is ViewModel with ICommand RemoveItem and ObservableCollection<FileViewModel> Files.

3
  • what is "failing to" you? - Please explain the error you get.... Commented Sep 29, 2011 at 8:27
  • Command is not bound... I don't get any error, just handler that is bound to command is never called Commented Sep 29, 2011 at 8:31
  • 1
    I think the Datacontext should just "rain down" onto your template, did you try Command="{Binding Path=RemoveItem}" ? Commented Sep 29, 2011 at 12:09

2 Answers 2

13

If you are on .NET 4 there indeed is a more elegant solution:

<UserControl Name="uc" ...> <!-- ... --> <MenuItem Header="Remove" Command="{Binding DataContext.RemoveItem, Source={x:Reference uc}}"/> 

(This requires that the template stays in the Resources, otherwise there will be a cyclical dependency error)

Sign up to request clarification or add additional context in comments.

3 Comments

can you elaborate on the dependency error? i have a similar situation where I'm using ElementName=LayoutRoot to get to the DataContext (my ViewModel). but it's leaking the viewmodel. would this be the cyclical depency error you're talking about? any way to resolve this? (windows store app btw)
@JorisWeimar: Dependency errors only occur for x:Reference in case you reference a control from within its tree, e.g. if a Grid contains a TextBlock and you try to reference the Grid in a binding on the TextBlock that would cause such an error. I only use x:Reference here because ElementName does not work in the context of disconnected trees. Regarding your problem, i don't understand what "leaking the viewmodel" is supposed to mean.
with leaking the viewmodel i mean that the viewmodel is not finalized because there there is a refence to it somewhere from within the COM layer (what i've gathered from PerfView). it almost seems that this is an inherent problem with this type of construction.
4

Menus are not drawn in the same Visual Tree as your Controls, which is why the RelativeSource binding does not work

You need to bind to the PlacementTarget of your ContextMenu to access the main Visual Tree

<MenuItem Header="Remove" Command="{Binding PlacementTarget.DataContext.RemoveItem, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ContextMenu}}}" /> 

5 Comments

Hm... I'm still not able to call a command. I see what's your point but binding doesn't work.
@Pedala I could have the syntax wrong. I know you want to bind to PlacementTarget, which should return the Control that the ContextMenu is attached to, but you may need to use a different syntax to navigate to the Command
Binding you wrote goes up to Grid (the one inside DataTemplate), but not up to the UserControl's DataContext(where command is). It's question whether is possible to nest Bindings, so I can go up from this grid?
@pedala I don't think it is, but you might be able to bind ContextMenu.DataContext to the UserControl's DataContext using a RelativeSource binding.
I've bound Grid's Tag attribute to {Binding RelativeSource={RelativeSource FindAncestor, AncestorType=UserControl}, Path=DataContext} and MenuItem to {Binding PlacementTarget.Tag.RemoveItem, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ContextMenu}}} It's working now, but still I belive there's some more elegant solution...

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.