简体   繁体   English

从父级的父级DataContext中的ContextMenu中的绑定属性

[英]Binding property in ContextMenu from Parent's Parent's DataContext

I wanted to bind a property in a MenuItem within an ItemsControl container. 我想在ItemsControl容器内的MenuItem绑定一个属性。 I have a hierarchical model ; 我有一个层次模型; Item class has a list of SubItem . Item类具有SubItem列表。 The ViewModel itself has a list of Item (so there's two ItemsControl , one being in the ItemTemplate of the other). ViewModel本身有一个Item列表(所以有两个ItemsControl ,一个在另一个的ItemTemplate中)。

I found several other questions on SO asking about that ( this one for instance ) and I learned that the Visual Tree of a ContextMenu is separated from the rest. 我在SO上发现了其他几个问题( 例如这个问题),并且我了解到ContextMenu的可视树与其余ContextMenu分开了。

I managed to do it and it works (but it feels kind of hacky) by "transferring" the model's data via the Tag property. 我设法做到了,并且通过Tag属性“传输”了模型的数据,它可以工作(但感觉有点怪异)。

Here's the two model classes: 这是两个模型类:

public class SubItem
{
    public int Current { get; set; }

    public Subitem(int current)
    {
        Current = current;
    }
}

public class Item
{
    public ObservableCollection<SubItem> SubItems { get; set; }

    public string Parent { get; set; }

    public Item(string Parent)
    {
        Parent = Parent;
        SubItems = new ObservableCollection<SubItem>();
    }
}

Here's the view model: 这是视图模型:

public class ViewModel
{
    public ObservableCollection<Item> Items { get; set; } 

    public ViewModel()
    {
        Items = new ObservableCollection<Item>();
        FillData();
    }

    private void FillData()
    {
        //...
    }
}

And here's the ItemsControl at the root of the page (the page's DataContext is an instance of the ViewModel class): 这是页面根目录中的ItemsControl (页面的DataContextViewModel类的实例):

<ItemsControl ItemsSource="{Binding Items}">
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <ItemsControl ItemsSource="{Binding SubItems}">
                <ItemsControl.ItemTemplate>
                    <DataTemplate>
                        <TextBlock Text="{Binding Current}"
                                   Tag="{Binding DataContext.Parent, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}, Mode=FindAncestor}}">
                            <TextBlock.ContextMenu>
                                <ContextMenu>
                                    <MenuItem Header="{Binding Path=PlacementTarget.Tag, RelativeSource={RelativeSource AncestorType={x:Type ContextMenu}, Mode=FindAncestor}}"/>
                                </ContextMenu>
                            </TextBlock.ContextMenu>
                        </TextBlock>
                    </DataTemplate>
                </ItemsControl.ItemTemplate>
            </ItemsControl>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

My question is: is this the right way to do it? 我的问题是:这是正确的方法吗? I tried many other ways to avoid binding the property to the Tag but couldn't make it work. 我尝试了许多其他方法来避免将属性绑定到Tag但是无法使其正常工作。

The ugly part is specifically: 丑陋的部分是:

Tag="{Binding DataContext.Parent, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}, Mode=FindAncestor}}" 

Followed by: 其次是:

Header="{Binding Path=PlacementTarget.Tag, RelativeSource={RelativeSource AncestorType={x:Type ContextMenu}, Mode=FindAncestor}}"

I think it's kind of ugly and I'm sure there's a better way to do that. 我认为这很丑陋,而且我敢肯定有更好的方法可以做到这一点。 The solution must work with .NET 4.0 . 该解决方案必须与.NET 4.0

You need to add a tag to the menu's container and bind to it using placement target. 您需要在菜单的容器中添加标签,然后使用放置目标将其绑定。

View this example: 查看此示例:

<StackPanel x:Key="ConfigurationListItem" x:Shared="False" Tag="{Binding ElementName=UserControl}">
        <StackPanel Orientation="Horizontal">
            <Button>
                <Button.InputBindings>
                    <MouseBinding Gesture="LeftDoubleClick" Command="{Binding ElementName=UserControl, Path=LaunchCommand}" CommandParameter="{Binding}" />
                    <MouseBinding Gesture="LeftClick" Command="{Binding ElementName=UserControl, Path=SelectCommand}" CommandParameter="{Binding}" />
                </Button.InputBindings>
        </StackPanel>

        <StackPanel.ContextMenu>
            <ContextMenu DataContext="{Binding Path=PlacementTarget.Tag, RelativeSource={RelativeSource Self}}" Tag="{Binding}">
                <MenuItem Header="Sync Environment Dependencies" 
                        Command="{Binding Parent.PlacementTarget.Tag.SyncEnvironmentCommand, RelativeSource={RelativeSource Self}}"
                        CommandParameter="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ContextMenu}}, Path=PlacementTarget.DataContext}" />
            </ContextMenu>
        </StackPanel.ContextMenu>
    </StackPanel>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM