30

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.

Rasto
  • 17,204
  • 47
  • 154
  • 245
  • Where are you trying to get that instance from? Is it from the `ItemsControl` or from one of the item templates inside it? – Dan Puzey Jan 20 '11 at 10:14
  • From `ItemsPanelTemplate` exactly. I definitely don't want to get it from item templates. – Rasto Jan 20 '11 at 14:58
  • Did I understand your question correctly or were you looking for something else? – Fredrik Hedblad Jan 21 '11 at 00:10
  • @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. – Rasto Jan 21 '11 at 13:33

4 Answers4

21

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.

Community
  • 1
  • 1
Fredrik Hedblad
  • 83,499
  • 23
  • 264
  • 266
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.

thumbmunkeys
  • 20,606
  • 8
  • 62
  • 110
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?

Community
  • 1
  • 1
dain
  • 6,475
  • 1
  • 38
  • 47
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);
    }