Comment obtenir les enfants d’un conteneur WPF par type?

Comment obtenir les contrôles enfants de type ComboBox dans MyContainer Grid dans WPF?

   

Cette ligne me donne une erreur:

 var myCombobox = this.MyContainer.Children.GetType(ComboBox); 

Cette méthode d’extension recherchera de manière récursive des éléments enfants du type souhaité:

 public static T GetChildOfType(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(child); if (result != null) return result; } return null; } 

Vous pouvez donc demander MyContainer.GetChildOfType() .

Children est une collection de UIElements. Vous devez donc parcourir les éléments et déterminer pour chaque élément s’il est du type requirejs. Heureusement, il existe déjà une méthode Linq pour cela, à savoir Enumerable.OfType , que vous pouvez facilement appeler à l’aide de la syntaxe Extension Method :

 var comboBoxes = this.MyContainer.Children.OfType(); 

Cette méthode filtre la collection en fonction de leur type et renvoie, dans votre cas, uniquement les éléments de type ComboBox .

Si vous voulez seulement le premier ComboBox (comme le suggère votre nom de variable), vous pouvez simplement append un appel à FirstOrDefault() à la requête:

 var myComboBox = this.MyContainer.Children.OfType().FirstOrDefault(); 

Recherchez le premier enfant d’un certain type comprenant un point prédéterminé (de l’écran):

(param ‘point’ est le résultat de l’appel de la fonction ‘PointToScreen’ (déclarée dans un type visuel))

 private TDescendantType FindDescendant(DependencyObject parent, Point screenPoint) where TDescendantType : DependencyObject { int count = VisualTreeHelper.GetChildrenCount(parent); for (int i = 0; i < count; i++) { var child = VisualTreeHelper.GetChild(parent, i); if (child is Visual) { Point point = ((Visual)child).PointFromScreen(screenPoint); Rect rect = VisualTreeHelper.GetDescendantBounds((Visual)child); if (!rect.Contains(point)) continue; } if (child is TDescendantType) { return (TDescendantType)child; } child = FindDescendant(child, screenPoint); if (child != null) { return (TDescendantType)child; } } return null; } 

Toutes ces réponses, sauf une, utilisent la récursivité pour laquelle l’ OMI est boiteuse 🙂

Obtenez des enfants visuels:

 public static IEnumerable FindVisualChildren([NotNull] this DependencyObject parent) where T : DependencyObject { if (parent == null) throw new ArgumentNullException(nameof(parent)); var queue = new Queue(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); } } } 

Obtenez des enfants logiques:

 public static IEnumerable FindLogicalChildren([NotNull] this DependencyObject parent) where T : DependencyObject { if (parent == null) throw new ArgumentNullException(nameof(parent)); var queue = new Queue(new[] {parent}); while (queue.Any()) { var reference = queue.Dequeue(); var children = LogicalTreeHelper.GetChildren(reference); var objects = children.OfType(); foreach (var o in objects) { if (o is T child) yield return child; queue.Enqueue(o); } } } 

Notez que les deux arbres traversent profondément, si vous souhaitez vous arrêter lors de la première rencontre, modifiez les deux codes pour englober l'appel à queue.Enqueue dans un bloc else .

Toutes ces réponses sont très bien, mais si vous essayez de trouver un enfant visuel de type T, vous êtes soit obligé de tous les obtenir et ensuite de trouver celui que vous voulez, soit en espérant que le premier celui que vous voulez. J’ai fusionné plusieurs approches pour en trouver une spécifique en fonction d’un critère. C’est un peu comme LINQ, mais je ne voulais pas essayer de traiter avec un énumérateur récursif.

Utilisez-le comme ceci:

 MyContainer.FirstOrDefaultChild 

Je l’ai écrit comme une méthode d’extension.

 public static class DependencyObjectExtensions { public static T FirstOrDefaultChild(this DependencyObject parent, Func selector) where T : DependencyObject { T foundChild; return FirstOrDefaultVisualChildWhere(parent, selector, out foundChild) ? foundChild : default(T); } private static bool FirstOrDefaultVisualChildWhere(DependencyObject parent, Func selector, out T foundChild) where T : DependencyObject { var count = VisualTreeHelper.GetChildrenCount(parent); for (var i = 0; i < count; i++) { var child = VisualTreeHelper.GetChild(parent, i); var tChild = child as T; if (tChild != null) { if (!selector(tChild)) continue; foundChild = tChild; return true; } if (FirstOrDefaultVisualChildWhere(child, selector, out foundChild)) { return true; } } foundChild = default(T); return false; }