【问题标题】:Cannot find source for binding with reference 'RelativeSource FindAncestor, AncestorType='System.Windows.Controls.UserControl', AncestorLevel='1''找不到与引用'RelativeSource FindAncestor,AncestorType ='System.Windows.Controls.UserControl',AncestorLevel ='1''的绑定源
【发布时间】:2018-09-01 23:24:16
【问题描述】:

我正在尝试基于 MVVM 中的分层数据模板在树视图中设置上下文菜单。 根是一个父视图模型,它在可观察集合中嵌套了视图模型,依此类推。根基于我的主视图模型

例子:

  • 父母
    • 儿童
      • 孙子 1
      • 孙子2
    • 孩子 2
      • 孙子 1
    • 孩子 3

我尝试做的是在一个名为“删除”的 Grand Child 上设置一个上下文菜单。我遇到的问题是,当它位于子视图模型中时,如何在上下文菜单中设置命令?因为所有 Grand 孩子都存储在子视图模型中的 observablecollection 中。 我尝试了这里发布的几个解决方案,但对我没有任何帮助。

到目前为止我尝试了什么:

  • 使用 Tag 属性和 Placementtarget

但我得到了错误:

找不到与引用“RelativeSource FindAncestor, AncestorType='SimTableApplication.View.Controls.VirtualControllerView', AncestorLevel='1'' 的绑定源。 BindingExpression:(无路径);数据项=空;目标元素是'StackPanel'(名称='');目标属性是“标签”(类型“对象”)

这是我的树视图的 xaml 代码:

 <TreeView Name="Tree" ItemsSource="{Binding Projects}" Background="#cccccc" BorderThickness="0" >
                    <i:Interaction.Behaviors>
                        <behav:TreeViewSelectedItemBehavior SelectedItem="{Binding SelectedTreeViewItem}"/>
                    </i:Interaction.Behaviors>
                    <TreeView.Resources>
                        <Style TargetType="TreeViewItem">
                            <Setter Property="IsExpanded" Value="True"/>
                            <Setter Property="Foreground" Value="White"/>
                            <Setter Property="FontWeight" Value="Bold"/>
                            <Setter Property="Background" Value="Transparent"/>
                            <EventSetter Event="MouseRightButtonDown" Handler="TreeViewItem_MouseRightButtonDown"/>
                        </Style>                        
                    </TreeView.Resources>
                    <TreeView.ItemTemplate>
                        <HierarchicalDataTemplate ItemsSource="{Binding VirtualPLCs}">
                            <StackPanel Orientation="Horizontal">
                                <Image Source="/SimTableApplication;component/Assets/ICO_PE_Project.ico" Height="18" Width="18"/>
                                <TextBlock Text="{Binding ProjModel.ProjectName}" Margin="3"/>
                                <StackPanel.ContextMenu>
                                    <ContextMenu>
                                        <MenuItem Header="Add new Controller" Command="{Binding AddNewControllerCommand}">
                                            <MenuItem.Icon>
                                                <Image Source="/SimTableApplication;component/Assets/ICO_PE_CreateNewItem.ico"/>
                                            </MenuItem.Icon>
                                        </MenuItem>
                                        <Separator />
                                        <MenuItem Header="Properties" Command="{Binding ShowProjectPropertiesCommand}">
                                            <MenuItem.Icon>
                                                <Image Source="/SimTableApplication;component/Assets/ICO_PVS_Properties.png"/>
                                            </MenuItem.Icon>
                                        </MenuItem>
                                    </ContextMenu>
                                </StackPanel.ContextMenu>
                            </StackPanel>
                            <HierarchicalDataTemplate.ItemTemplate>
                                <HierarchicalDataTemplate ItemsSource="{Binding SimTables}">
                                    <StackPanel Orientation="Horizontal">
                                        <Image Source="/SimTableApplication;component/Assets/ICO_PE_Device.ico" Height="18" Width="18"/>
                                        <TextBlock Text="{Binding Name}" Margin="3"/>
                                        <StackPanel.ContextMenu>
                                            <ContextMenu>
                                                <MenuItem Header="Add new SIM table" Command="{Binding AddNewSimTableCommand}">
                                                    <MenuItem.Icon>
                                                        <Image Source="/SimTableApplication;component/Assets/ICO_PE_CreateNewItem.ico"/>
                                                    </MenuItem.Icon>
                                                </MenuItem>
                                                <Separator />
                                                <MenuItem Header="Power On" Command="{Binding PowerOnCommand}">
                                                    <MenuItem.Icon >
                                                        <Image Source="/SimTableApplication;component/Assets/ICO_PLCSIM_Tbon.ico "/>
                                                    </MenuItem.Icon>
                                                </MenuItem>
                                                <MenuItem Header="Power Off" Command="{Binding PowerOffCommand}">
                                                    <MenuItem.Icon >
                                                        <Image Source="/SimTableApplication;component/Assets/ICO_PLCSIM_Tboff.ico "/>
                                                    </MenuItem.Icon>
                                                </MenuItem>
                                                <MenuItem Header="Run" Command="{Binding RunCommand}">
                                                    <MenuItem.Icon >
                                                        <Image Source="/SimTableApplication;component/Assets/StartSimulation.png"/>
                                                    </MenuItem.Icon>
                                                </MenuItem>
                                                <MenuItem Header="Stop" Command="{Binding StopCommand}">
                                                    <MenuItem.Icon >
                                                        <Image Source="/SimTableApplication;component/Assets/StopSimulation.png"/>
                                                    </MenuItem.Icon>
                                                </MenuItem>
                                                <MenuItem Header="MRES" Command="{Binding ResetMemoryCardCommand}">
                                                    <MenuItem.Icon >
                                                        <Image Source="/SimTableApplication;component/Assets/reset-icon.png"/>
                                                    </MenuItem.Icon>
                                                </MenuItem>
                                                <Separator />
                                                <MenuItem Header="Delete">
                                                    <MenuItem.Icon>
                                                        <Image Source="/SimTableApplication;component/Assets/ICO_PE_TbDelete.ico"/>
                                                    </MenuItem.Icon>
                                                </MenuItem>
                                            </ContextMenu>
                                        </StackPanel.ContextMenu>
                                    </StackPanel>
                                    <HierarchicalDataTemplate.ItemTemplate >
                                        <DataTemplate >
                                            <StackPanel Orientation="Horizontal" **Tag="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserControl}}}">**
                                                <Image Source="/SimTableApplication;component/Assets/ICO_PLCS_SimTable.ico" Height="18" Width="18"/>
                                                <TextBlock  Text="{Binding SimTableName}"  Margin="3"/>
                                                <StackPanel.ContextMenu>
                                                    <ContextMenu>
                                                        <MenuItem Header="Delete"  Command="{Binding Path=PlacementTarget.Tag.DataContext.DeleteSimTableCommand,
                                                    RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ContextMenu}}">
                                                            <MenuItem.Icon>
                                                                <Image Source="/SimTableApplication;component/Assets/ICO_PE_TbDelete.ico"/>
                                                            </MenuItem.Icon>
                                                        </MenuItem>
                                                    </ContextMenu>
                                                </StackPanel.ContextMenu>
                                            </StackPanel>
                                        </DataTemplate>
                                    </HierarchicalDataTemplate.ItemTemplate>
                                </HierarchicalDataTemplate>
                            </HierarchicalDataTemplate.ItemTemplate>
                        </HierarchicalDataTemplate>
                    </TreeView.ItemTemplate>

                </TreeView>

也许有人可以提示我做错了什么。

【问题讨论】:

    标签: c# wpf mvvm


    【解决方案1】:

    我认为您的问题是因为您试图同时进行相对源绑定和放置目标。我不认为我曾经设法让它按预期工作。 我通常做的是将placementtarget的标签绑定到我要从中获取命令的任何地方,然后我就可以到达那里。如果您在该上下文菜单中有其他命令,这可能是一个问题,但您没有。 我没有你所有的代码,所以我把一些东西放在一起只有两个层次——父母和孩子。 Child 是叶子,而 parent 相当于您的删除命令所在的位置。 这对我有用:

    <Window.DataContext>
        <local:MainWindowViewModel/>
    </Window.DataContext>
    <Grid>
        <TreeView ItemsSource="{Binding Parents}">
            <TreeView.Resources>
                <HierarchicalDataTemplate DataType="{x:Type local:Parent}" ItemsSource="{Binding Children}">
                        <TextBlock Text="{Binding Name}" />
                </HierarchicalDataTemplate>
                <DataTemplate DataType="{x:Type local:Child}">
                    <StackPanel Tag="{Binding DataContext, 
                            RelativeSource={RelativeSource AncestorType=TreeViewItem , AncestorLevel=2}
                            }" 
                           >
                        <StackPanel.ContextMenu>
                            <ContextMenu DataContext="{Binding Path=PlacementTarget.Tag,
                                         RelativeSource={x:Static RelativeSource.Self}}">
                                <MenuItem Header="Delete"  Command="{Binding DeleteCommand}">
                                </MenuItem>
                            </ContextMenu>
                        </StackPanel.ContextMenu>
                        <TextBlock Text="{Binding ChildName}"/>
                    </StackPanel>
                </DataTemplate>
            </TreeView.Resources>
        </TreeView>
    </Grid>
    

    标签在可视树中,所以它可以做相对源的事情OK,然后命令在放置目标的标签中。 如果不清楚,我可以发布示例。

    删除键绑定会更简单,但我想这对你没有好处。

    【讨论】:

    • 谢谢你的例子。这适用于只有一个上下文菜单的情况。但是,如果我有多个条目和不同的数据上下文,我该怎么办?
    • 有很多方法可以处理这个问题。您可以将更复杂的对象放在具有多个依赖项属性的标签中。它们可以绑定到您喜欢的任何地方。使用标签虽然不是很优雅。另一种选择是使用标记为继承的附加依赖属性。然后,任何逻辑子级都将继承该属性。我从来没有在树视图项目中尝试过,并且很难让继承来处理自定义属性。
    • 如果您的要求真的很复杂,那么您可能会发现定义一个从控件继承但没有 ui 的类更简单。将其添加到父树视图项的模板中,然后使用其中的代码设置子项的附加属性。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-03-07
    • 2016-04-08
    • 2012-08-16
    • 1970-01-01
    • 2011-04-23
    • 2011-01-18
    • 2011-03-12
    相关资源
    最近更新 更多