Alois Kraus
Alois Kraus

Reputation: 13535

ContextMenu Binding from a TreeView

I have a simple task to bind a context menu to items in a TreeView. If I define the context menu statically no problem. But if I want to bind the context menu to my "root" data context things start to break. So far I was not able to find a correct way to bind my Context menu to the original DataContext the TreeView uses. What binding magic is need to get this working? This Binding does not work:

  <MenuItem Name="Name" Header="{Binding Path=DataContext.ContextMenuName, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type TreeView}}}" />

Below is the full sample:

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:sys="clr-namespace:System;assembly=mscorlib"
        xmlns:ui="clr-namespace:WpfApplication1"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <TreeView ItemsSource="{Binding Path=Persons, Mode=OneTime}" Name="cTree">
            <TreeView.ItemTemplate>
                <HierarchicalDataTemplate>
                    <TextBox Text="{Binding Mode=OneWay}">
                        <TextBox.ContextMenu>
                            <ContextMenu>
                                <MenuItem Name="Name" Header="{Binding Path=DataContext.ContextMenuName, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type TreeView}}}" />
                            </ContextMenu>
                        </TextBox.ContextMenu>
                    </TextBox>
                </HierarchicalDataTemplate>
            </TreeView.ItemTemplate>
        </TreeView>
    </Grid>
</Window>



public partial class MainWindow : Window
{
    public string[] Persons
    {
        get { return new string[] { "Alois", "Kraus", "Joe", "xxxx" }; }
    }

    public string ContextMenuName
    {
        get;
        set;
    }

    public MainWindow()
    {
        ContextMenuName = "This is the data bound menu name";
        InitializeComponent();
        this.DataContext = this;
    }
}

Basically I want to bind the property ContextMenuName (actually a command in my ViewModel) of the main form. Since the TreeView is rebinding its childs to the Persons (strings to keep it simple) I cannot get the root DataContext out of it. So far I was never able to find any Ancestor (TreeView or MainWindow) which should solve the issue? What am I doing wrong here?

Upvotes: 3

Views: 168

Answers (2)

Rohit Vats
Rohit Vats

Reputation: 81253

ContextMenu doesn't lie in same visual tree as that of control on which it is applied. So FindAncestor won't be able to get to TreeView since it is not ancestor of ContextMenu.

Also ElementName won't work here since it also need two controls to be in same Visual tree.

You can use x:Reference which allows to bind even if they don't lie in same visual tree:

<MenuItem Name="Name" 
          Header="{Binding Path=DataContext.ContextMenuName,
                           Source={x:Reference cTree}}" />

Upvotes: 6

Iain
Iain

Reputation: 2550

Have you tried binding via ElementName=cTree instead of RelativeSource={...}?

Upvotes: 0

Related Questions