Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get instance of Panel that holds content of ItemsControl?

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.

like image 614
Rasto Avatar asked Jan 20 '11 07:01

Rasto


3 Answers

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.

like image 62
Fredrik Hedblad Avatar answered Nov 06 '22 07:11

Fredrik Hedblad


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.

like image 29
thumbmunkeys Avatar answered Nov 06 '22 07:11

thumbmunkeys


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?

like image 2
dain Avatar answered Nov 06 '22 06:11

dain