Ich muss eine WPF-Steuerelementhierarchie nach Steuerelementen durchsuchen, die einem bestimmten Namen oder Typ entsprechen. Wie kann ich das machen?
Ich habe das von John Myczek und Tri Qs Algorithmus verwendete Vorlagenformat kombiniert, um einen findChild-Algorithmus zu erstellen, der für jedes übergeordnete Element verwendet werden kann. Denken Sie daran, dass das rekursive Durchsuchen eines Baums nach unten ein langwieriger Prozess sein kann. Ich habe dies nur in einer WPF-Anwendung vor Ort überprüft. Bitte kommentieren Sie eventuelle Fehler und ich werde meinen Code korrigieren.
WPF Snoop ist ein nützliches Werkzeug zum Betrachten des visuellen Baums. Ich würde dringend empfehlen, ihn beim Testen zu verwenden oder diesen Algorithmus zu verwenden, um Ihre Arbeit zu überprüfen.
Es gibt einen kleinen Fehler im Tri Q-Algorithmus. Nachdem das Kind gefunden wurde, können wir das korrekt gefundene Kind überschreiben, wenn Kinderzahl> 1 ist und wir erneut iterieren. Deshalb habe ich ein if (foundChild != null) break;
in meinen Code eingefügt , um mit dieser Bedingung umzugehen.
/// <summary>
/// Finds a Child of a given item in the visual tree.
/// </summary>
/// <param name="parent">A direct parent of the queried item.</param>
/// <typeparam name="T">The type of the queried item.</typeparam>
/// <param name="childName">x:Name or Name of child. </param>
/// <returns>The first parent item that matches the submitted type parameter.
/// If not matching item can be found,
/// a null parent is being returned.</returns>
public static T FindChild<T>(DependencyObject parent, string childName)
where T : DependencyObject
{
// Confirm parent and childName are valid.
if (parent == null) return null;
T foundChild = null;
int childrenCount = VisualTreeHelper.GetChildrenCount(parent);
for (int i = 0; i < childrenCount; i++)
{
var child = VisualTreeHelper.GetChild(parent, i);
// If the child is not of the request child type child
T childType = child as T;
if (childType == null)
{
// recursively drill down the tree
foundChild = FindChild<T>(child, childName);
// If the child is found, break so we do not overwrite the found child.
if (foundChild != null) break;
}
else if (!string.IsNullOrEmpty(childName))
{
var frameworkElement = child as FrameworkElement;
// If the child's name is set for search
if (frameworkElement != null && frameworkElement.Name == childName)
{
// if the child's name is of the request name
foundChild = (T)child;
break;
}
}
else
{
// child element found.
foundChild = (T)child;
break;
}
}
return foundChild;
}
Nennen Sie es so:
TextBox foundTextBox =
UIHelper.FindChild<TextBox>(Application.Current.MainWindow, "myTextBoxName");
Hinweis Application.Current.MainWindow
kann ein beliebiges übergeordnetes Fenster sein.
FrameworkElement
als T übergeben, wird er null zurückgeben, sobald die erste Schleife endet. Sie müssen also einige Änderungen vornehmen.Sie können ein Element auch mit FrameworkElement.FindName (Zeichenfolge) nach Namen suchen .
Gegeben:
In die CodeBehind-Datei können Sie schreiben:
Da es mit x: Name definiert ist, können Sie natürlich nur auf das generierte Feld verweisen, aber vielleicht möchten Sie es dynamisch und nicht statisch nachschlagen.
Dieser Ansatz ist auch für Vorlagen verfügbar, bei denen das benannte Element mehrmals angezeigt wird (einmal pro Verwendung der Vorlage).
quelle
Sie können den VisualTreeHelper verwenden , um Steuerelemente zu finden. Im Folgenden finden Sie eine Methode, die mithilfe von VisualTreeHelper ein übergeordnetes Steuerelement eines angegebenen Typs findet. Sie können den VisualTreeHelper verwenden, um Steuerelemente auch auf andere Weise zu finden.
Nennen Sie es so:
quelle
Ich wiederhole vielleicht nur alle anderen, aber ich habe einen hübschen Code, der die DependencyObject-Klasse mit einer Methode FindChild () erweitert, mit der Sie das Kind nach Typ und Name erhalten. Einfach einschließen und verwenden.
Ich hoffe, Sie finden es nützlich.
quelle
Meine Erweiterungen zum Code.
Quelle: https://code.google.com/p/gishu-util/source/browse/#git%2FWPF%2FUtilities
Erklärender Blog-Beitrag: http://madcoderspeak.blogspot.com/2010/04/wpf-find-child-control-of-specific-type.html
quelle
Wenn Sie ALLE Steuerelemente eines bestimmten Typs finden möchten, könnte Sie auch dieses Snippet interessieren
quelle
child
ein zweites Mal? Wenn SiechildType
Typ habenT
, können Sie in das schreibenif
:yield return childType
... nein?Dadurch werden einige Elemente verworfen. Sie sollten es so erweitern, um eine größere Auswahl an Steuerelementen zu unterstützen. Eine kurze Diskussion finden Sie hier
quelle
Try*
Methode zurückgibtbool
und einenout
Parameter hat, der den fraglichen Typ zurückgibt, wie bei:bool IDictionary.TryGetValue(TKey key, out TValue value)
FindParent
. Dieser Name impliziert für mich, dass er zurückkehren könntenull
. DasTry*
Präfix wird in der gesamten BCL wie oben beschrieben verwendet. Beachten Sie auch, dass die meisten anderen Antworten hier dieFind*
Namenskonvention verwenden. Es ist jedoch nur ein kleiner Punkt :)Ich habe den Code von CrimsonX bearbeitet, da er nicht mit Typen der Oberklasse funktioniert:
quelle
DependencyObject
, die keine istFrameworkElement
, kann dies eine Ausnahme auslösen. Auch die VerwendungGetChildrenCount
bei jeder Iteration derfor
Schleife klingt nach einer schlechten Idee.Obwohl ich Rekursion im Allgemeinen liebe, ist sie beim Programmieren in C # nicht so effizient wie Iteration. Vielleicht ist die folgende Lösung besser als die von John Myczek vorgeschlagene? Dadurch wird eine Hierarchie aus einem bestimmten Steuerelement durchsucht, um ein Vorfahrensteuerelement eines bestimmten Typs zu finden.
Nennen Sie es so, um das
Window
Steuerelement zu finden, das heißtExampleTextBox
:quelle
Hier ist mein Code, um Steuerelemente nach Typ zu finden und gleichzeitig zu steuern, wie tief wir in die Hierarchie vordringen (maxDepth == 0 bedeutet unendlich tief).
quelle
exciton80 ... Ich hatte ein Problem mit Ihrem Code, der nicht durch Benutzersteuerungen wiederkehrte. Es traf die Gitterwurzel und warf einen Fehler. Ich glaube, das behebt es für mich:
quelle
Ich habe eine Sequenzfunktion wie diese (die völlig allgemein ist):
Sofortige Kinder bekommen:
Alle Kinder im hiararchischen Baum finden:
Sie können dies im Fenster aufrufen, um alle Steuerelemente abzurufen.
Nachdem Sie die Sammlung haben, können Sie LINQ (dh OfType, Where) verwenden.
quelle
Da die Frage allgemein genug ist, um Menschen anzulocken, die nach Antworten auf sehr triviale Fälle suchen: Wenn Sie nur ein Kind und keinen Nachkommen wollen, können Sie Linq verwenden:
oder natürlich die offensichtliche Schleife, die über Kinder iteriert.
quelle
Diese Optionen sprechen bereits über das Durchlaufen des visuellen Baums in C #. Es ist möglich, den visuellen Baum auch in xaml mit der RelativeSource-Markup-Erweiterung zu durchlaufen. msdn
nach Typ finden
quelle
Hier ist eine Lösung, die ein flexibles Prädikat verwendet:
Sie können es zum Beispiel so nennen:
quelle
Dieser Code behebt nur den Fehler der @ CrimsonX-Antwort:
Sie müssen die Methode nur rekursiv weiter aufrufen, wenn die Typen übereinstimmen, die Namen jedoch nicht (dies geschieht, wenn Sie
FrameworkElement
als übergebenT
). sonst wird es zurückkehrennull
und das ist falsch.quelle
Um einen Vorfahren eines bestimmten Typs aus dem Code zu finden, können Sie Folgendes verwenden:
Diese Implementierung verwendet eine Iteration anstelle einer Rekursion, die etwas schneller sein kann.
Wenn Sie C # 7 verwenden, kann dies etwas kürzer gemacht werden:
quelle
Versuche dies
Code dahinter
quelle