如何获取包含 ItemsControl 内容的 Panel 实例?

Posted

技术标签:

【中文标题】如何获取包含 ItemsControl 内容的 Panel 实例?【英文标题】:How to get instance of Panel that holds content of ItemsControl? 【发布时间】:2011-06-12 07:03:40 【问题描述】:

每个ItemsControl 都将其内容存储在 Panel 中,对吗?我们可以像这样指定要在 XAML 中使用的面板:

<ListView Name="LView">
    <ListView.ItemsPanel>
        <ItemsPanelTemplate >
            <StackPanel/>
        </ItemsPanelTemplate>
     </ListView.ItemsPanel>
</ListView>

我的问题是如何获取在特定 ItemsControlItemsPanel 属性(类型为 ItemsPanelTemplate)中使用的 Panel 的实例?例如上面的代码示例中的ListView 调用LView

我不能使用Name 属性或x:Name,这必须适用于任何ItemsControl,即使是使用默认ItemsPanel 的那些。

如果不清楚请发表评论,我认为有非常简单的解决方案。如果它看起来很复杂,那只是因为我无法正确解释它。

【问题讨论】:

您想从哪里获取该实例?是来自ItemsControl 还是来自其中的某个项目模板? 完全来自ItemsPanelTemplate。我绝对不想从项目模板中获取它。 我是否正确理解了您的问题,还是您正在寻找其他内容? @Meleak:在pivotnig 的回答之后,我能够找到一些解决方案——我所需要的只是有一个VisualTreeHelper 类。我的代码看起来与您提供的非常相似,我不确定差异 - 我不确定我的代码是否总是有效(可能存在一些我不知道的泄漏......)。一段时间后我会接受其中一个答案。 【参考方案1】:

这有点棘手,因为您不知道面板的名称,因此您不能使用 FindName 等。这适用于存在 ItemsPresenter 的大多数情况

private Panel GetItemsPanel(DependencyObject itemsControl)

    ItemsPresenter itemsPresenter = GetVisualChild<ItemsPresenter>(itemsControl);
    Panel itemsPanel = VisualTreeHelper.GetChild(itemsPresenter, 0) as Panel;
    return itemsPanel;

GetVisualChild 的实现

private static T GetVisualChild<T>(DependencyObject parent) where T : Visual

    T child = default(T);

    int numVisuals = VisualTreeHelper.GetChildrenCount(parent);
    for (int i = 0; i < numVisuals; i++)
    
        Visual v = (Visual)VisualTreeHelper.GetChild(parent, i);
        child = v as T;
        if (child == null)
        
            child = GetVisualChild<T>(v);
        
        if (child != null)
        
            break;
        
    
    return child;

但是,并不总是使用 ItemsPanel。请参阅 Ian Griffiths 的 this answer 以获得很好的解释。

【讨论】:

【参考方案2】:

我无法为您提供工作代码,但请看一下 VisualTreeHelper class。 使用VisualTreeHelper 类,您可以遍历可视化树到您的模板和面板。

【讨论】:

【参考方案3】:
protected Panel ItemsHost 
    get 
        return (Panel) typeof (MultiSelector).InvokeMember("ItemsHost",
            BindingFlags.NonPublic | BindingFlags.GetProperty | BindingFlags.Instance,
            null, this, null);
    

这在我的ItemsControl 中就像一个魅力!也就是说,它内部的Panel 上确实有IsItemsHost="True",但即使没有它也可以工作。

技巧来自这个帖子:Can I access ItemsHost of ItemsControl using reflection?

【讨论】:

【参考方案4】:
   private object FindItemControl(ItemsControl itemsControl, string controlName, object item)
    
        ContentPresenter container = itemsControl.ItemContainerGenerator.ContainerFromItem(item) as ContentPresenter;
        container.ApplyTemplate();
        return container.ContentTemplate.FindName(controlName, container);
    

【讨论】:

以上是关于如何获取包含 ItemsControl 内容的 Panel 实例?的主要内容,如果未能解决你的问题,请参考以下文章

某些项目未通过 ItemsSource 显示在 ItemsControl 中

在ItemsControl中更紧密的项目

如何使用 DataTrigger 更改 ItemsControl 中的 ItemsPanel?

ItemsControl - 网格子元素自动调整大小

绑定到包含 ItemsControl 数据的 UserControl

嵌套 ItemsControl 的拉伸高度