2009-05-17 9 views

Répondre

7

classe pour obtenir une liste de tous les composants des enfants d'un contrôle:

class Utility 
    { 
     private static StringBuilder sbListControls; 

     public static StringBuilder GetVisualTreeInfo(Visual element) 
     { 
      if (element == null) 
      { 
       throw new ArgumentNullException(String.Format("Element {0} is null !", element.ToString())); 
      } 

      sbListControls = new StringBuilder(); 

      GetControlsList(element, 0); 

      return sbListControls; 
     } 

     private static void GetControlsList(Visual control, int level) 
     { 
      const int indent = 4; 
      int ChildNumber = VisualTreeHelper.GetChildrenCount(control); 

      for (int i = 0; i <= ChildNumber - 1; i++) 
      { 
       Visual v = (Visual)VisualTreeHelper.GetChild(control, i); 

       sbListControls.Append(new string(' ', level * indent)); 
       sbListControls.Append(v.GetType()); 
       sbListControls.Append(Environment.NewLine); 

       if (VisualTreeHelper.GetChildrenCount(v) > 0) 
       { 
        GetControlsList(v, level + 1); 
       } 
      } 
     } 
    } 
+2

Le fait de ne pas boucler dans l'arborescence logique est meilleur et efficace que de boucler dans l'arborescence visuelle. – MegaMind

+0

'sbListControls' devrait être une variable locale, juste au cas où ces méthodes sont appelées en même temps par plusieurs threads. –

14

Je trouve cela dans le MSDN documenation il aide.

// Enumerate all the descendants of the visual object. 
static public void EnumVisual(Visual myVisual) 
{ 
    for (int i = 0; i < VisualTreeHelper.GetChildrenCount(myVisual); i++) 
    { 
     // Retrieve child visual at specified index value. 
     Visual childVisual = (Visual)VisualTreeHelper.GetChild(myVisual, i); 

     // Do processing of the child visual object. 

     // Enumerate children of the child visual object. 
     EnumVisual(childVisual); 
    } 
} 

Cela me semble plus simple. Je l'ai utilisé pour trouver des zones de texte dans un formulaire et effacer leurs données.

+0

J'ai posté une autre réponse basée sur ceci qui retourne effectivement un 'IEnumerable ' de sorte que l'utilisateur final puisse simplement utiliser une boucle normale, etc. Ceci rend l'énumération de la collection d'enfants très simple, et permet l'avortement anticipé via 'break; 'etc. Jetez un coup d'oeil. – BrainSlugs83

+0

Lorsque j'essaie de reproduire ceci, j'obtiens une erreur sur myVisual (par exemple .GetChildrenCount (** myVisual **) & .GetChild (** myVisual **, i)) en disant "impossible de convertir depuis 'Windows.UI.Composition.Visual 'à' Windows.UI.Xaml.DependencyObject '"? Les solutions WPF fonctionnent-elles dans l'environnement UWP? Est-ce que j'utilise la mauvaise directive using (Windows.UI.Composition)? – gaw

0

Une légère variation de la réponse MSDN ... il suffit de passer dans une liste vide d'objets visuels dans votre collection et sera peuplée avec tous les visuels de l'enfant:

/// <summary> 
/// Enumerate all the descendants (children) of a visual object. 
/// </summary> 
/// <param name="parent">Starting visual (parent).</param> 
/// <param name="collection">Collection, into which is placed all of the descendant visuals.</param> 
public static void EnumVisual(Visual parent, List<Visual> collection) 
{ 
    for (int i = 0; i < VisualTreeHelper.GetChildrenCount(parent); i++) 
    { 
     // Get the child visual at specified index value. 
     Visual childVisual = (Visual)VisualTreeHelper.GetChild(parent, i); 

     // Add the child visual object to the collection. 
     collection.Add(childVisual); 

     // Recursively enumerate children of the child visual object. 
     EnumVisual(childVisual, collection); 
    } 
} 
+0

J'ai posté une autre réponse basée sur la vôtre qui renvoie effectivement un 'IEnumerable ' de sorte que l'utilisateur final puisse simplement utiliser une boucle for-normale, etc. Cela économise le temps de création d'une liste et permet un avortement anticipé via 'break; 'etc. Jetez un coup d'oeil. – BrainSlugs83

8

De cette façon, est supérieure à la Méthode MSDN, en ce sens qu'il est réutilisable, et permet l'abandon prématuré de la boucle (par exemple, break;, etc.) - il optimise la boucle for en ce qu'il enregistre un appel de méthode pour chaque itération - et il vous permet également d'utiliser régulièrement pour que les boucles circulent à travers les enfants d'un Visual, ou même pour recurse ses enfants et ses grands enfants - il est donc beaucoup plus simple de consommer.

A consommer, vous pouvez simplement écrire une boucle régulière foreach (ou même utiliser LINQ):

foreach (var ctrl in myWindow.GetChildren()) 
{ 
    // Process children here! 
} 

Ou si vous ne voulez pas récursif:

foreach (var ctrl in myWindow.GetChildren(false)) 
{ 
    // Process children here! 
} 

Pour le rendre travail, vous avez juste besoin de mettre cette méthode d'extension dans une classe statique, et puis vous serez capable d'écrire du code comme ci-dessus quand vous le souhaitez:

public static IEnumerable<Visual> GetChildren(this Visual parent, bool recurse = true) 
{ 
    if (parent != null) 
    { 
     int count = VisualTreeHelper.GetChildrenCount(parent); 
     for (int i = 0; i < count; i++) 
     { 
      // Retrieve child visual at specified index value. 
      var child = VisualTreeHelper.GetChild(parent, i) as Visual; 

      if (child != null) 
      { 
       yield return child; 

       if (recurse) 
       { 
        foreach (var grandChild in child.GetChildren(true)) 
        { 
         yield return grandChild; 
        } 
       } 
      } 
     } 
    } 
} 

En outre, si vous ne souhaitez pas que la récursivité soit activée par défaut, vous pouvez modifier la déclaration de la méthode d'extension afin que recurse = false devienne le comportement par défaut.

1

J'ai utilisé ce qui suit pour obtenir tous les contrôles.

public static IList<Control> GetControls(this DependencyObject parent) 
    {    
     var result = new List<Control>(); 
     for (int x = 0; x < VisualTreeHelper.GetChildrenCount(parent); x++) 
     { 
      DependencyObject child = VisualTreeHelper.GetChild(parent, x); 
      var instance = child as Control; 

      if (null != instance) 
       result.Add(instance); 

      result.AddRange(child.GetControls()); 
     } 
     return result; 
    } 
Questions connexes