Binding an Ancestor not working WPF

2020-04-11 11:38发布

问题:

I've got a TreeView, which is modified to show Images in front of the text too. So my modified TreeViewItem is called ImagedTreeViewItem. This ImagedTreeViewItem has a Property, that contains the Image for Image-Control to show. The ImagedTreeViewItem has also a property, that checks, if the ImagedTreeViewItem-Icon is a folder-Icon. This Property has the name "IsFolder".

My Problem is: I'm Binding the Ancestors-Property (here: The ImagedTreeViewItem) to get the data I need. For my Image-Control it works perfectly, for a Context Menu I added later not. I don't understand why, because basically it is the same command.

Here is the Code of my "ImagedTreeView" in XAML:

<TreeView.Resources>
                <Style TargetType="{x:Type myClasses:ImagedTreeViewItem}">
                    <Setter Property="HeaderedItemsControl.HeaderTemplate">
                        <Setter.Value>
                            <DataTemplate>
                                <StackPanel Orientation="Horizontal">
<!-- Here it works!!! -->
                                    <Image Height="16" Source="{Binding Path=Icon, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type myClasses:ImagedTreeViewItem}}}" Stretch="Fill" Width="16" />
                                    <TextBlock Margin="5,0" Text="{Binding}" />
                                    <StackPanel.ContextMenu>
                                        <ContextMenu>
<!-- Here not :( -->
                                            <MenuItem Command="my:ImagedTreeView.AddFolder" Header="Add Folder"
                                                              IsEnabled="{Binding Path=IsFolder,
                                                              RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type myClasses:ImagedTreeViewItem}}}">
                                                <MenuItem.Icon>
                                                    <Image Source="folderadd16.png" />
                                                </MenuItem.Icon>
                                            </MenuItem>
                                            <!-- ... -->
                                        </ContextMenu>
                                    </StackPanel.ContextMenu>
                                </StackPanel>
                            </DataTemplate>
                        </Setter.Value>
                    </Setter>
                </Style>
            </TreeView.Resources>

I think the second binding in this code cannot find the ancestor. The output-window of Visual Studio tells me the same:

System.Windows.Data Error: 4 : Cannot find source for binding with reference 'RelativeSource FindAncestor, AncestorType='....ImagedTreeViewItem', AncestorLevel='1''. BindingExpression:Path=IsFolder; DataItem=null; target element is 'MenuItem' (Name=''); target property is 'IsEnabled' (type 'Boolean')

回答1:

ContextMenu is not part of the VisualTree, that's why the binding fails. You have to use some kind of relay: ContextMenu.PlacementTarget and Tag property as a cache for the second trail of binding search. I think this will work:

<StackPanel Orientation="Horizontal"
            Tag="{Binding RelativeSource={RelativeSource AncestorType={x:Type myClasses:ImagedTreeViewItem}}}">
    <StackPanel.ContextMenu>
        <ContextMenu>
            <MenuItem Command="my:ImagedTreeView.AddFolder" Header="Add Folder"
                      IsEnabled="{Binding Path=PlacementTarget.Tag.IsFolder, RelativeSource={RelativeSource AncestorType=ContextMenu}}">
                <MenuItem.Icon>
                    <Image Source="folderadd16.png" />
                </MenuItem.Icon>
            </MenuItem>
            <!-- ... -->
        </ContextMenu>
    </StackPanel.ContextMenu>