Suchen Sie alle Steuerelemente in WPF-Fenster nach Typ

Ich suche nach einer Möglichkeit, alle Steuerelemente von Windows nach ihrem Typ zu finden,

Zum Beispiel: finde alle TextBoxes , finde alle Steuerelemente, die eine bestimmte Schnittstelle implementieren usw.

   

Dies sollte den Trick machen

 public static IEnumerable FindVisualChildren(DependencyObject depObj) where T : DependencyObject { if (depObj != null) { for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++) { DependencyObject child = VisualTreeHelper.GetChild(depObj, i); if (child != null && child is T) { yield return (T)child; } foreach (T childOfChild in FindVisualChildren(child)) { yield return childOfChild; } } } } 

dann zählst du über die Kontrollen so auf

 foreach (TextBlock tb in FindVisualChildren(window)) { // do something with tb here } 

Dies ist der einfachste Weg:

 IEnumerable collection = control.Children.OfType(); 

wo Kontrolle das Wurzelelement des Fensters ist.

Ich passte @ Bryce Kahles Antwort an, um @Mathias Lykkegaard Lorenzens Vorschlag zu folgen und LogicalTreeHelper zu verwenden.

Scheint gut zu funktionieren. 😉

  public static IEnumerable FindLogicalChildren ( 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( child ) ) { yield return childOfChild; } } } } } 

(Es wird immer noch nicht überprüfen Tab-Controls oder Grids in GroupBoxen wie @Benjamin Berry und @David R jeweils erwähnt.) (Auch gefolgt @ Mittagunds Vorschlag & entfernt das redundante Kind! = Null)

Verwenden Sie die VisualTreeHelper oder LogicalTreeHelper je nachdem, an welcher Baumstruktur Sie interessiert sind. Beide bieten Methoden zum VisualTreeHelper LogicalTreeHelper Elemente eines Elements (obwohl sich die Syntax ein wenig unterscheidet). Ich benutze diese classn oft, um das erste Vorkommen eines bestimmten Typs zu finden, aber Sie könnten es leicht ändern, um alle Objekte dieses Typs zu finden:

 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; } 

Ich fand, dass die Zeile, VisualTreeHelper.GetChildrenCount (depObj);, die in einigen Beispielen oben verwendet wird, keine Zahl ungleich null für GroupBoxes zurückgibt, insbesondere wenn die GroupBox ein Grid enthält und das Grid untergeordnete Elemente enthält. Ich glaube, dies kann daran liegen, dass die GroupBox nicht mehr als ein Kind enthalten darf, und dies wird in der Content-Eigenschaft gespeichert. Es gibt keinen GroupBox.Children-Eigenschaftstyp. Ich bin mir sicher, dass ich das nicht sehr effizient gemacht habe, aber ich habe das erste “FindVisualChildren” -Beispiel in dieser Kette wie folgt modifiziert:

  public IEnumerable FindVisualChildren(DependencyObject depObj) where T : DependencyObject { if (depObj != null) { int depObjCount = VisualTreeHelper.GetChildrenCount(depObj); for (int i = 0; i (child)) { yield return childOfChild; } } } } 

Um eine Liste aller Childs eines bestimmten Typs zu erhalten, können Sie Folgendes verwenden:

 private static IEnumerable FindInVisualTreeDown(DependencyObject obj, Type type) { if (obj != null) { if (obj.GetType() == type) { yield return obj; } for (var i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++) { foreach (var child in FindInVisualTreeDown(VisualTreeHelper.GetChild(obj, i), type)) { if (child != null) { yield return child; } } } } yield break; } 

Kleine Änderung an der Rekursion nach, so dass Sie zum Beispiel die untergeordnete Registerkarte eines Tab-Steuerelements finden können.

  public static DependencyObject FindInVisualTreeDown(DependencyObject obj, Type type) { if (obj != null) { for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++) { DependencyObject child = VisualTreeHelper.GetChild(obj, i); if (child.GetType() == type) { return child; } DependencyObject childReturn = FindInVisualTreeDown(child, type); if (childReturn != null) { return childReturn; } } } return null; } 

Und so funktioniert es aufwärts

  private T FindParent(DependencyObject item, Type StopAt) where T : class { if (item is T) { return item as T; } else { DependencyObject _parent = VisualTreeHelper.GetParent(item); if (_parent == null) { return default(T); } else { Type _type = _parent.GetType(); if (StopAt != null) { if ((_type.IsSubclassOf(StopAt) == true) || (_type == StopAt)) { return null; } } if ((_type.IsSubclassOf(typeof(T)) == true) || (_type == typeof(T))) { return _parent as T; } else { return FindParent(_parent, StopAt); } } } } 

Beachten Sie, dass die Verwendung von VisualTreeHelper nur für Steuerelemente funktioniert, die von Visual oder Visual3D abgeleitet sind. Wenn Sie auch andere Elemente (z. B. TextBlock, FlowDocument usw.) überprüfen müssen, triggers das Verwenden von VisualTreeHelper eine Ausnahme aus.

Hier ist eine Alternative, die bei Bedarf auf den logischen Baum zurückgreift:

http://www.hardcodet.net/2009/06/finding-elements-in-wpf-tree-both-ways

Hier ist noch eine weitere, kompakte Version mit der Generics-Syntax:

  public static IEnumerable FindLogicalChildren(DependencyObject obj) where T : DependencyObject { if (obj != null) { if (obj is T) yield return obj as T; foreach (DependencyObject child in LogicalTreeHelper.GetChildren(obj).OfType()) foreach (T c in FindLogicalChildren(child)) yield return c; } } 

Ich wollte einen Kommentar hinzufügen, aber ich habe weniger als 50 Punkte, so dass ich nur “antworten” kann. Beachten Sie, dass, wenn Sie die “VisualTreeHelper” -Methode verwenden, um XAML “TextBlock” -Objekte abzurufen, auch XAML- “Button” -Objekte erfasst werden. Wenn Sie das Objekt “TextBlock” erneut initialisieren, indem Sie in den Parameter Textblock.Text schreiben, können Sie den Button-Text nicht mehr mit dem Parameter Button.Content ändern. Der Button zeigt permanent den Text an, der von der Schreibaktion Textblock.Text geschrieben wurde

 foreach (TextBlock tb in FindVisualChildren(window)) { // do something with tb here tb.Text = ""; //this will overwrite Button.Content and render the //Button.Content{set} permanently disabled. } 

Um dies zu umgehen, können Sie versuchen, eine XAML-TextBox zu verwenden und Methoden (oder Ereignisse) hinzuzufügen, um eine XAMAL-Schaltfläche nachzuahmen. XAML “TextBox” wird nicht durch eine Suche nach “TextBlock” gesammelt.

Meine Version für C ++ / CLI

 template < class T, class U > bool Isinst(U u) { return dynamic_cast< T >(u) != nullptr; } template  T FindVisualChildByType(Windows::UI::Xaml::DependencyObject^ element, Platform::String^ name) { if (Isinst(element) && dynamic_cast(element)->Name == name) { return dynamic_cast(element); } int childcount = Windows::UI::Xaml::Media::VisualTreeHelper::GetChildrenCount(element); for (int i = 0; i < childcount; ++i) { auto childElement = FindVisualChildByType(Windows::UI::Xaml::Media::VisualTreeHelper::GetChild(element, i), name); if (childElement != nullptr) { return childElement; } } return nullptr; }; 

Aus irgendeinem Grund half mir keine der hier geposteten Antworten, alle Steuerelemente eines bestimmten Typs zu erhalten, die in einem bestimmten Steuerelement in meinem MainWindow enthalten sind. Ich musste alle Menüpunkte in einem Menü finden, um sie zu iterieren. Sie waren nicht alle direkt von der Speisekarte abstammend, also gelang es mir, nur die erste von ihnen zu sammeln, indem ich irgendeinen der obigen Codes verwendete. Diese Erweiterungsmethode ist meine Lösung für das Problem für jeden, der weiter unten lesen wird.

 public static void FindVisualChildren(this ICollection children, DependencyObject depObj) where T : DependencyObject { if (depObj != null) { var brethren = LogicalTreeHelper.GetChildren(depObj); var brethrenOfType = LogicalTreeHelper.GetChildren(depObj).OfType(); foreach (var childOfType in brethrenOfType) { children.Add(childOfType); } foreach (var rawChild in brethren) { if (rawChild is DependencyObject) { var child = rawChild as DependencyObject; FindVisualChildren(children, child); } } } } 

Ich hoffe es hilft.

Wirklich nette Antwort.

VB.NET-Version:

 Public Shared Iterator Function FindVisualChildren(Of T As DependencyObject)(depObj As DependencyObject) As IEnumerable(Of T) If depObj IsNot Nothing Then For i As Integer = 0 To VisualTreeHelper.GetChildrenCount(depObj) - 1 Dim child As DependencyObject = VisualTreeHelper.GetChild(depObj, i) If child IsNot Nothing AndAlso TypeOf child Is T Then Yield DirectCast(child, T) End If For Each childOfChild As T In FindVisualChildren(Of T)(child) Yield childOfChild Next Next End If End Function 

Verwendung (dies deaktiviert alle TextBoxen in einem Fenster):

  For Each tb As TextBox In FindVisualChildren(Of TextBox)(Me) tb.IsEnabled = False Next 

Ich fand es einfacher ohne Visual Tree Helpers:

 foreach (UIElement element in MainWindow.Children) { if (element is TextBox) { if ((element as TextBox).Text != "") { //Do something } } };