236 votes

Trouver tous les contrôles dans WPF Window par type

Je cherche un moyen de trouver tous les contrôles de Window par leur type,

par exemple : trouver tous TextBoxes trouver tous les contrôles implémentant une interface spécifique, etc.

0 votes

Tant que nous sommes sur le sujet, ceci est également pertinent goo.gl/i9RVx

0 votes

J'ai également écrit un article de blog sur le sujet : Modifier un ControlTemplate à l'exécution

458voto

Bryce Kahle Points 3937

Cela devrait faire l'affaire :

public static IEnumerable<T> FindVisualChilds<T>(DependencyObject depObj) where T : DependencyObject
{
    if (depObj == null) yield return (T)Enumerable.Empty<T>();
    for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
    {
        DependencyObject ithChild = VisualTreeHelper.GetChild(depObj, i);
        if (ithChild == null) continue;
        if (ithChild is T t) yield return t;
        foreach (T childOfChild in FindVisualChilds<T>(ithChild)) yield return childOfChild;
    }
}

puis on énumère les contrôles comme suit

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

72 votes

Remarque : si vous essayez de faire fonctionner cette méthode et que vous constatez que votre fenêtre (par exemple) n'a pas d'enfants visuels, essayez d'exécuter cette méthode dans le gestionnaire d'événements Loaded. Si vous l'exécutez dans le constructeur (même après InitializeComponent()), les enfants visuels ne sont pas encore chargés, et cela ne fonctionnera pas.

0 votes

FxCop va attraper ça, référez-vous msdn.microsoft.com/library/ms182150(VS.90).aspx

0 votes

Cela ne fonctionnera pas pour les enfants qui ne sont pas chargés mais présents. Par exemple, caché par Expander. Comment faire une énumération de tous les enfants ?

73voto

Joel Points 6958

C'est le moyen le plus simple :

IEnumerable<myType> collection = control.Children.OfType<myType>(); 

où control est l'élément Root de la fenêtre.

EDIT - Comme indiqué dans les commentaires. Cela ne va qu'à un seul niveau de profondeur. Voir la réponse acceptée pour une option qui va plus loin.

1 votes

Que voulez-vous dire par "élément principal" ? Que dois-je écrire pour me connecter à mon formulaire mainwindow ?

1 votes

Je comprends, dans la vue xaml j'ai dû définir le nom de la grille. <Grid Name="Anata_wa_yoru_o_shihai_suru_ai">here buttons</Grid> et ensuite je pourrais utiliser Anata_wa_yoru_o_shihai_suru_ai.Children.OfType<myType>();

72 votes

Cela ne répond pas à la question qui a été posée. Elle ne renvoie que les contrôles enfants d'un niveau de profondeur.

26voto

Simon F Points 87

J'ai adapté la réponse de @Bryce Kahle pour suivre la suggestion de @Mathias Lykkegaard Lorenzen et utiliser LogicalTreeHelper .

Ça a l'air de bien fonctionner ;)

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

(Il ne vérifie toujours pas les contrôles de tabulation ou les grilles à l'intérieur de GroupBoxes comme mentionné par @Benjamin Berry & @David R respectivement). (J'ai également suivi la suggestion de @noonand et supprimé le redondant child != null)

0 votes

Je cherche depuis un moment comment effacer toutes mes zones de texte, j'ai plusieurs onglets et c'est le seul code qui a fonctionné :) merci

0 votes

Ceci a mieux fonctionné pour moi, donne un résultat plat Enumerator pour les enfants imbriqués (MenuItems dans mon cas)

14voto

Oskar Points 3009

Utilisez les classes d'aide VisualTreeHelper o LogicalTreeHelper en fonction des arbre qui vous intéressent. Elles fournissent toutes deux des méthodes pour obtenir les enfants d'un élément (bien que la syntaxe diffère un peu). J'utilise souvent ces classes pour trouver la première occurrence d'un type spécifique, mais vous pourriez facilement les modifier pour trouver tous les objets de ce type :

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

0 votes

+1 pour l'explication et le post mais Bryce Kahle a posté une fonction qui fonctionne parfaitement Merci

0 votes

Cela ne résout pas le problème de la question, et la réponse avec le type générique est également beaucoup plus claire. En la combinant avec l'utilisation de VisualTreeHelper.GetChildrenCount(obj), le problème sera résolu. Cependant, il est utile de la considérer comme une option.

10voto

David R Points 51

J'ai trouvé que la ligne, VisualTreeHelper.GetChildrenCount(depObj); utilisé dans plusieurs exemples ci-dessus, ne renvoie pas un nombre non nul pour l'option GroupBox es, en particulier, lorsque l GroupBox contient un Grid et le Grid contient des éléments enfants. Je pense que cela peut être dû au fait que le GroupBox n'est pas autorisé à contenir plus d'un enfant, et ceci est stocké dans sa section Content la propriété. Il n'y a pas de GroupBox.Children type de propriété. Je suis sûr que je n'ai pas fait cela très efficacement, mais j'ai modifié le premier exemple "FindVisualChildren" de cette chaîne comme suit :

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

            if (child is GroupBox)
            {
                GroupBox gb = child as GroupBox;
                Object gpchild = gb.Content;
                if (gpchild is T)
                {
                    yield return (T)child; 
                    child = gpchild as T;
                }
            }

            foreach (T childOfChild in FindVisualChildren<T>(child)) 
            { 
                yield return childOfChild; 
            } 
        }
    }
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X