Problem
I’m seeking for a way to sort all of the controls on the Window by type.
Find all TextBoxes, for example, or all controls that implement a given interface.
Asked by Andrija
Solution #1
This ought to suffice:
public static IEnumerable<T> FindVisualChilds<T>(DependencyObject depObj) where T : DependencyObject
{
if (depObj == null) yield return (T)Enumerable.Empty<T>();
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
{
DependencyObject ithChild = VisualTreeHelper.GetChild(depObj, i);
if (ithChild == null) continue;
if (ithChild is T t) yield return t;
foreach (T childOfChild in FindVisualChilds<T>(ithChild)) yield return childOfChild;
}
}
Then you go over the controls one by one, like this.
foreach (TextBlock tb in FindVisualChildren<TextBlock>(window))
{
// do something with tb here
}
Answered by Bryce Kahle
Solution #2
The simplest method is:
IEnumerable<myType> collection = control.Children.OfType<myType>();
The root element of the window is called control.
EDIT: As pointed out in the comments, this is incorrect. This only goes up one notch. For a more in-depth option, see the acceptable answer.
Answered by Joel
Solution #3
I modified @Bryce Kahle’s response to utilize LogicalTreeHelper as suggested by @Mathias Lykkegaard Lorenzen.
It appears to be working properly. 😉
public static IEnumerable<T> FindLogicalChildren<T> ( DependencyObject depObj ) where T : DependencyObject
{
if( depObj != null )
{
foreach( object rawChild in LogicalTreeHelper.GetChildren( depObj ) )
{
if( rawChild is DependencyObject )
{
DependencyObject child = (DependencyObject)rawChild;
if( child is T )
{
yield return (T)child;
}
foreach( T childOfChild in FindLogicalChildren<T>( child ) )
{
yield return childOfChild;
}
}
}
}
}
(As @Benjamin Berry and @David R pointed out, it still won’t verify tab controls or Grids inside GroupBoxes.) (I also deleted the superfluous child!= null, as suggested by @noonand.)
Answered by Simon F
Solution #4
Depending on whatever tree you’re interested in, use the VisualTreeHelper or LogicalTreeHelper helper classes. They both give techniques for obtaining an element’s offspring (although the syntax differs a little). I frequently use these classes to identify the first instance of a particular type, but you could easily extend them to find all objects of that kind:
public static DependencyObject FindInVisualTreeDown(DependencyObject obj, Type type)
{
if (obj != null)
{
if (obj.GetType() == type)
{
return obj;
}
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++)
{
DependencyObject childReturn = FindInVisualTreeDown(VisualTreeHelper.GetChild(obj, i), type);
if (childReturn != null)
{
return childReturn;
}
}
}
return null;
}
Answered by Oskar
Solution #5
I discovered that the line VisualTreeHelper.GetChildrenCount(depObj); used in several of the examples above does not yield a non-zero count for GroupBoxes, especially when the GroupBox contains a Grid with children elements. I assume this is due to the fact that the GroupBox can only have one child, which is stored in its Content attribute. There is no such thing as a GroupBox. Property that is suitable for children. I’m sure I didn’t do it very well, but here’s how I changed the first “FindVisualChildren” example in this chain:
public IEnumerable<T> FindVisualChildren<T>(DependencyObject depObj) where T : DependencyObject
{
if (depObj != null)
{
int depObjCount = VisualTreeHelper.GetChildrenCount(depObj);
for (int i = 0; i <depObjCount; i++)
{
DependencyObject child = VisualTreeHelper.GetChild(depObj, i);
if (child != null && child is T)
{
yield return (T)child;
}
if (child is GroupBox)
{
GroupBox gb = child as GroupBox;
Object gpchild = gb.Content;
if (gpchild is T)
{
yield return (T)child;
child = gpchild as T;
}
}
foreach (T childOfChild in FindVisualChildren<T>(child))
{
yield return childOfChild;
}
}
}
}
Answered by David R
Post is based on https://stackoverflow.com/questions/974598/find-all-controls-in-wpf-window-by-type