J'ai besoin de rechercher dans une hiérarchie de contrôles WPF des contrôles qui correspondent à un nom ou un type donné. Comment puis-je faire ceci?
J'ai combiné le format de modèle utilisé par John Myczek et l'algorithme de Tri Q ci-dessus pour créer un algorithme findChild qui peut être utilisé sur n'importe quel parent. Gardez à l'esprit que la recherche récursive d'un arbre vers le bas peut être un processus long. J'ai seulement vérifié cela sur une application WPF, veuillez commenter les erreurs que vous pourriez trouver et je corrigerai mon code.
WPF Snoop est un outil utile pour regarder l'arborescence visuelle - je vous recommande fortement de l'utiliser pendant les tests ou d'utiliser cet algorithme pour vérifier votre travail.
Il y a une petite erreur dans l'algorithme de Tri Q. Une fois l'enfant trouvé, si le nombre d'enfants est> 1 et que nous réitérons, nous pouvons remplacer l'enfant trouvé correctement. J'ai donc ajouté un if (foundChild != null) break;
dans mon code pour faire face à cette condition.
/// <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;
}
Appelez ça comme ceci:
TextBox foundTextBox =
UIHelper.FindChild<TextBox>(Application.Current.MainWindow, "myTextBoxName");
La note Application.Current.MainWindow
peut être n'importe quelle fenêtre parente.
FrameworkElement
en T, il retournera null dès que la première boucle se terminera. donc tu vas devoir faire quelques modifications.Vous pouvez également rechercher un élément par son nom à l'aide de FrameworkElement.FindName (chaîne) .
Donné:
Dans le fichier code-behind, vous pouvez écrire:
Bien sûr, car il est défini à l'aide de x: Name, vous pouvez simplement référencer le champ généré, mais vous souhaitez peut-être le rechercher de manière dynamique plutôt que statique.
Cette approche est également disponible pour les modèles, dans lesquels l'élément nommé apparaît plusieurs fois (une fois par utilisation du modèle).
la source
Vous pouvez utiliser VisualTreeHelper pour rechercher des contrôles. Vous trouverez ci-dessous une méthode qui utilise VisualTreeHelper pour rechercher un contrôle parent d'un type spécifié. Vous pouvez également utiliser VisualTreeHelper pour rechercher d'autres contrôles.
Appelez ça comme ceci:
la source
Je répète peut-être tout le monde, mais j'ai un joli morceau de code qui étend la classe DependencyObject avec une méthode FindChild () qui vous donnera l'enfant par type et nom. Il suffit d'inclure et d'utiliser.
J'espère que vous le trouverez utile.
la source
Mes extensions au code.
Source: https://code.google.com/p/gishu-util/source/browse/#git%2FWPF%2FUtilities
Article de blog explicatif: http://madcoderspeak.blogspot.com/2010/04/wpf-find-child-control-of-specific-type.html
la source
Si vous souhaitez trouver TOUS les contrôles d'un type spécifique, cet extrait pourrait également vous intéresser
la source
child
une deuxième fois? Si vous avezchildType
du typeT
, vous pouvez écrire à l'intérieur duif
:yield return childType
... non?Cela supprimera certains éléments - vous devez l'étendre comme ceci afin de prendre en charge un plus large éventail de contrôles. Pour une brève discussion, jetez un œil ici
la source
Try*
méthode retournebool
et ait unout
paramètre qui retourne le type en question, comme avec:bool IDictionary.TryGetValue(TKey key, out TValue value)
FindParent
. Ce nom pour moi implique qu'il pourrait revenirnull
. LeTry*
préfixe est utilisé dans toute la BCL de la manière que je décris ci-dessus. Notez également que la plupart des autres réponses ici utilisent laFind*
convention de dénomination. Ce n'est qu'un point mineur cependant :)J'ai édité le code de CrimsonX car il ne fonctionnait pas avec les types de superclasse:
la source
DependencyObject
qui n'est pas a,FrameworkElement
elle peut lever une exception. Utiliser également àGetChildrenCount
chaque itération de lafor
boucle sonne comme une mauvaise idée.Bien que j'aime la récursivité en général, ce n'est pas aussi efficace que l'itération lors de la programmation en C #, alors peut-être que la solution suivante est plus nette que celle suggérée par John Myczek? Cela recherche une hiérarchie à partir d'un contrôle donné pour trouver un contrôle ancêtre d'un type particulier.
Appelez-le comme ceci pour trouver le
Window
contenant contenant un contrôle appeléExampleTextBox
:la source
Voici mon code pour trouver des contrôles par type tout en contrôlant la profondeur de la hiérarchie (maxDepth == 0 signifie infiniment profond).
la source
exciton80 ... J'avais un problème avec votre code qui ne se reproduisait pas via les contrôles utilisateur. Il atteignait la racine de la grille et lançait une erreur. Je crois que cela me corrige:
la source
J'ai une fonction de séquence comme celle-ci (qui est complètement générale):
Obtenir des enfants immédiats:
Trouver tous les enfants dans l'arbre hiararchique:
Vous pouvez appeler cela dans la fenêtre pour obtenir tous les contrôles.
Après avoir la collection, vous pouvez utiliser LINQ (c'est-à-dire OfType, Where).
la source
Puisque la question est suffisamment générale pour attirer des personnes à la recherche de réponses à des cas très triviaux: si vous voulez juste un enfant plutôt qu'un descendant, vous pouvez utiliser Linq:
ou bien sûr l'évidence pour l'itération de boucle sur les enfants.
la source
Ces options parlent déjà de la traversée de l'arborescence visuelle en C #. Il est également possible de parcourir l'arborescence visuelle dans xaml en utilisant l'extension de balisage RelativeSource. msdn
trouver par type
la source
Voici une solution qui utilise un prédicat flexible:
Vous pouvez par exemple l'appeler comme ceci:
la source
Ce code corrige simplement le bug de la réponse @CrimsonX:
Vous avez juste besoin de continuer à appeler la méthode de manière récursive si les types correspondent, mais pas les noms (cela se produit lorsque vous passez en
FrameworkElement
tant queT
). sinon ça va revenirnull
et c'est faux.la source
Pour trouver un ancêtre d'un type donné à partir du code, vous pouvez utiliser:
Cette implémentation utilise l'itération au lieu de la récursivité qui peut être légèrement plus rapide.
Si vous utilisez C # 7, cela peut être légèrement raccourci:
la source
Essaye ça
Code derrière
la source