Access ViewModel / DataConext inside ContextMenu
Asked Answered
L

1

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;
    ....
}
Lashio answered 26/7, 2011 at 0:28 Comment(0)
B
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...

Boothe answered 26/7, 2011 at 1:4 Comment(2)
This worked great! Thank you! You mentioned other libraries that might bridge this gap, would Prism be one of these?Lashio
Glad it helped :) I don't know if Prism has support for that, i just looked around again and this 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 quite a while ago but it was not of much use to me, maybe i applied it wrongly....Boothe

© 2022 - 2024 — McMap. All rights reserved.