How to get instance of Panel that holds content of ItemsControl?
Asked Answered
P

4

32

Every ItemsControl has its content stored in Panel right ? We can specify the panel to be used in XAML like this:

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

My question is how to get instance of Panel that is used in the ItemsPanel property (of type ItemsPanelTemplate) of the particular ItemsControl ? For example ListView called LView from above code sample?

I cannot use Name property or x:Name, this must work for any ItemsControl even those using default ItemsPanel.

In the case its not clear please comment, I think there is very simple solution. If it seems to be complicated that's only because I cannot explain it properly.

Potion answered 20/1, 2011 at 7:55 Comment(4)
Where are you trying to get that instance from? Is it from the ItemsControl or from one of the item templates inside it?Hydrobomb
From ItemsPanelTemplate exactly. I definitely don't want to get it from item templates.Potion
Did I understand your question correctly or were you looking for something else?Loos
@Meleak: I was able to figure out some solution after pivotnig's answer - all I needed was a fact that there is a VisualTreeHelper class. My code looks very similar to what you have provided, I'm not sure about defferences - and I'm not sure if my code always works (some leaks may be there that I'm not aware of...). I will accept one of answers after some time.Potion
L
23

It's a little tricky since you don't know the name of the Panel so you can't use FindName etc. This will work for most cases where an ItemsPresenter is present

private Panel GetItemsPanel(DependencyObject itemsControl)
{
    ItemsPresenter itemsPresenter = GetVisualChild<ItemsPresenter>(itemsControl);
    Panel itemsPanel = VisualTreeHelper.GetChild(itemsPresenter, 0) as Panel;
    return itemsPanel;
}

An implementation of 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;
}

However, the ItemsPanel isn't always used. See this answer by Ian Griffiths for a great explanation.

Loos answered 20/1, 2011 at 8:39 Comment(0)
N
3

I can't provide you with working code, but have a look at VisualTreeHelper class. With the VisualTreeHelper class you can traverse the visual tree down to your template and panel.

Nosh answered 20/1, 2011 at 8:25 Comment(0)
M
2
protected Panel ItemsHost {
    get {
        return (Panel) typeof (MultiSelector).InvokeMember("ItemsHost",
            BindingFlags.NonPublic | BindingFlags.GetProperty | BindingFlags.Instance,
            null, this, null);
    }
}

This works like a charm in my ItemsControl! That said, it does have IsItemsHost="True" on the Panel inside, but might even work without it.

Trick is from this thread: Can I access ItemsHost of ItemsControl using reflection?

Makepeace answered 26/1, 2012 at 15:49 Comment(0)
E
0
   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);
    }
Endless answered 30/5, 2021 at 23:33 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.