Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Access ViewModel / DataConext inside ContextMenu

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;
    ....
}
like image 294
Michael G Avatar asked Jul 26 '11 00:07

Michael G


1 Answers

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

like image 62
H.B. Avatar answered Nov 16 '22 14:11

H.B.