6

How can I get the original DataContext of the UserControl inside of a ContextMenu.

The code below, you can see that there is a Button in the DataTemplate, which binds correctly. However, when trying to bind the datasource of the contextmenu, I recieve the following error:

System.Windows.Data Error: 4 : Cannot find source for binding with reference 'RelativeSource FindAncestor, AncestorType='System.Windows.Controls.TreeView', AncestorLevel='1''. BindingExpression:Path=DataContext; DataItem=null; target element is 'ContextMenu' (Name=''); target property is 'DataContext' (type 'Object')

What do I need to do to allow the ContextMenu to bind to the ViewModel?

===============================================================================

The ViewModel is assigned to the datacontext of the view in the codebehind:

View:

<TreeView ItemsSource="{Binding Clients}"
          cmd:TreeViewSelect.Command="{Binding SelectionChangedCommand}"
          cmd:TreeViewSelect.CommandParameter="{Binding RelativeSource={RelativeSource Self},Path=SelectedItem}">
    <TreeView.ItemTemplate>
        <DataTemplate>
            <StackPanel>
                <TextBlock Text="{Binding Name}">
                    <TextBlock.ContextMenu>
                        <ContextMenu DataContext="{Binding DataContext, 
                            RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type TreeView}}}">
                            <MenuItem Header="{Binding TestString}" />
                        </ContextMenu>
                    </TextBlock.ContextMenu>
                </TextBlock>

                <Button  DataContext="{Binding DataContext, 
                            RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type TreeView}}}"
                         Content="{Binding TestString}" Command="{Binding EditSelectedClientCommand}" />
             </StackPanel>
        </DataTemplate>
    </TreeView.ItemTemplate>
</TreeView>

ViewModel:

public class ClientListViewModel : ViewModelBase
{
    public String TestString { 
        get {
            return "TESTING";  
        }
    }

    private ClientList _clients = null;
    private readonly IClientService _clientService = null;
    private readonly IEventAggregator _eventAggregator = null;
    private Client _selectedClient = null;
    private ICommand _selectionChangedCommand = null;
    private ICommand _editSelectedClientCommand = null;
    ....
}
H.B.
  • 166,899
  • 29
  • 327
  • 400
Michael G
  • 6,695
  • 2
  • 41
  • 59

1 Answers1

10

ContextMenus do not appear in the visual tree which causes RelativeSource-bindings to fail, you can still get the DataContext one way or another though. You could try this for example:

<TextBlock Text="{Binding Name}"
           Tag="{Binding DataContext, RelativeSource={RelativeSource AncestorType=TreeView}}">
    <TextBlock.ContextMenu>
        <ContextMenu DataContext="{Binding PlacementTarget.Tag, RelativeSource={RelativeSource Self}}">
            <MenuItem Header="{Binding TestString}" />
            <!-- ... --->

The PlacementTarget is the TextBlock, and the DataContext is tunneled through the Tag. Just one way to do this (at least i hope it works), i have also seen some libraries which bridge this gap differently but i do not recall their origin...

H.B.
  • 166,899
  • 29
  • 327
  • 400
  • This worked great! Thank you! You mentioned other libraries that might bridge this gap, would Prism be one of these? – Michael G Jul 26 '11 at 02:09
  • Glad it helped :) I don't know if Prism has support for that, i just looked around again and [this](http://www.codeproject.com/KB/WPF/AttachingVirtualBranches.aspx) would be one of those libraries i have come accross earlier but i do not know if it would work in this scenario as i think that i never actually used it. I however tried out another thing called the [DataContextSpy](http://www.codeproject.com/KB/WPF/ArtificialInheritanceCxt.aspx) quite a while ago but it was not of much use to me, maybe i applied it wrongly.... – H.B. Jul 26 '11 at 02:18
  • The Tag property is what I was missing! Thank you! – Jarek Mitek Aug 13 '13 at 04:36