I am sure many of you have had a need to dig into an ItemsControl to find the ItemsPanel.
If you are taking a top-down approach, which is more involved, you would have to rely on the VisualTreeHelper to drill down and then find the Panel instance you need. A bottom-up approach is more easier if you have a reference to a UI Container inside the ItemsControl. You could do ItemsControl.GetItemsOwner() and pass in a reference to your UI container to get back a reference to the ItemsControl. A slightly different way would be to walk up the parent chain manually and get at the ItemsControl.
Well, now I have a third way to get at an ItemsPanel. This time I use the hit-testing capabilities of the WPF framework to do the work.
Typically the ItemsPanel occupies most of the layout space inside an ItemsControl. So a Point at the center of the ItemsControl is a good hit-test point to check for an ItemsPanel. This is exactly what I do in the following snippet:
public T FindItemsPanel<T>(ItemsControl itemsControl)
where T : Panel
{
Point p = new Point(itemsControl.ActualWidth / 2,
itemsControl.ActualHeight / 2);
HitTestResult result = VisualTreeHelper.HitTest(itemsControl, p);
DependencyObject visual = result.VisualHit;
while (!(visual is T))
{
visual = VisualTreeHelper.GetParent(visual);
}
return visual as T;
}
In most cases, the hit-test directly gives the ItemsPanel, however if you have items inside the ItemsControl, the additional parent-chain walk is also necessary. In any case, this approach is lot more reliable and simple when you don’t have any reference to the contained visuals. Walking up the parent-chain is always easier than going top-down.
In fact this simulated hit-testing capability can be extended to find different kinds of UIElements in your visual tree. Think lookups in DataTemplates, ControlTemplates, etc. You can certainly use the FindName() API wherever applicable, but for certain cases the simulated hit-testing gives more predictable results with minimal work.
I have now developed a new love for hit-testing, rather simulated hit-testing ;-)