How to get children of a WPF container by type?
This extension method will search recursively for child elements of the desired type:
public static T GetChildOfType<T>(this DependencyObject depObj)
where T : DependencyObject
{
if (depObj == null) return null;
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
{
var child = VisualTreeHelper.GetChild(depObj, i);
var result = (child as T) ?? GetChildOfType<T>(child);
if (result != null) return result;
}
return null;
}
So using that you can ask for MyContainer.GetChildOfType<ComboBox>()
.
All of these answers but one uses recursion which IMO is just lame :)
Get visual children:
public static IEnumerable<T> FindVisualChildren<T>([NotNull] this DependencyObject parent) where T : DependencyObject
{
if (parent == null)
throw new ArgumentNullException(nameof(parent));
var queue = new Queue<DependencyObject>(new[] {parent});
while (queue.Any())
{
var reference = queue.Dequeue();
var count = VisualTreeHelper.GetChildrenCount(reference);
for (var i = 0; i < count; i++)
{
var child = VisualTreeHelper.GetChild(reference, i);
if (child is T children)
yield return children;
queue.Enqueue(child);
}
}
}
Get logical children:
public static IEnumerable<T> FindLogicalChildren<T>([NotNull] this DependencyObject parent) where T : DependencyObject
{
if (parent == null)
throw new ArgumentNullException(nameof(parent));
var queue = new Queue<DependencyObject>(new[] {parent});
while (queue.Any())
{
var reference = queue.Dequeue();
var children = LogicalTreeHelper.GetChildren(reference);
var objects = children.OfType<DependencyObject>();
foreach (var o in objects)
{
if (o is T child)
yield return child;
queue.Enqueue(o);
}
}
}
Note that both deeply traverse trees, if you wish to stop at first encounter then change both codes to encompass the call to queue.Enqueue
in an else
block.
Children is a collection of UIElements. So you need to iterate over the items and determine for each item whether it is of the required type. Fortunately, there is already a Linq method for exactly this, namely Enumerable.OfType<T>
, which you can conveniently call using Extension Method syntax:
var comboBoxes = this.MyContainer.Children.OfType<ComboBox>();
This method filters the collection based on their type and returns, in your case, only the elements of type ComboBox
.
If you only want the first ComboBox (as your variable name might suggest), you can just append a call to FirstOrDefault()
to the query:
var myComboBox = this.MyContainer.Children.OfType<ComboBox>().FirstOrDefault();