2010-01-26 5 views
2

J'ai besoin d'une méthode d'extension pour parcourir toutes les zones de texte sur ma page Silverlight. Supposons que j'utilise toujours une grille mise en page, j'ai:Méthode d'extension du finder d'élément silverlight récursive

public static IEnumerable<UIElement> Traverse(this UIElementCollection source, Func<Grid, UIElementCollection> fnRecurse) 
    { 
     foreach (UIElement item in source) 
     { 
      yield return item; 
      var g = source.OfType<Grid>(); 
      foreach (Grid itemsub in g) 
       { 
        var t = fnRecurse(itemsub); 
         t.Traverse(fnRecurse); 
         yield return itemsub; 

       }; 
     } 

    } 

Maintenant, je peux appeler cela comme tel:

baseLayout.Children.Traverse(x => x.Children).OfType<TextBox>().ForEach(
       w => 
       { 
        //Text Box Extension Method, clears the text 
        w.reset(); 
       }); 

Ce n'incendies. Je crois que c'est le OfType ne pas être capable de distinguer les éléments de l'interface utilisateur.

Comment est-ce que je ferais ceci? Je veux aplatir l'arbre visuel puis passer à travers. Pas seulement des textboxes mais tout simplement tout ce que je veux. Est-ce que je cède au mauvais endroit ou trop souvent?

Edit:

Code actuel

public static IEnumerable<UIElement> Traverse(this UIElementCollection source, Func<Grid, UIElementCollection> fnRecurse) 
    { 

     foreach (UIElement item in source) 
     { 
      source.OfType<Grid>().Select(x => x.Children).ForEach(v => Traverse(v, fnRecurse)); 
      yield return item; 
     } 

    } 

et la grille est

<Grid x:Name="LayoutRoot"> 
    <Grid.RowDefinitions> 
     <RowDefinition Height="42"/> 
     <RowDefinition Height="42"/> 
     <RowDefinition Height="45"/> 
     <RowDefinition Height="43"/> 
     <RowDefinition Height="47"/> 
     <RowDefinition Height="46"/> 
     <RowDefinition/> 
     <RowDefinition Height="67"/> 
    </Grid.RowDefinitions> 
    <Button x:Name="saveAddressButton" Height="24" HorizontalAlignment="Left" Margin="8,0,0,8" VerticalAlignment="Bottom" Width="135" Content="Save and Add More" Click="saveClick" Style="{StaticResource SaveButton}" Foreground="White" Grid.Row="7"/> 
    <Button x:Name="saveAddressButton_Copy" Height="24" HorizontalAlignment="Right" Margin="0,0,8,8" VerticalAlignment="Bottom" Width="81" Content="Clear" Click="clearClick" Style="{StaticResource SaveButton}" Foreground="White" Grid.Row="7"/> 
    <Grid Height="30" VerticalAlignment="Top" Margin="8,9,8,0"> 
     <TextBlock Margin="8,0,0,0" Text="AddressLine1" FontSize="16" Foreground="White" HorizontalAlignment="Left" Width="121"/> 
     <TextBox x:Name="inputAddressLine1" TextWrapping="Wrap" Margin="218,0,0,0"/> 
    </Grid> 
    <Grid Height="30" Margin="8,8,8,0" VerticalAlignment="Top" Grid.Row="2"> 
     <TextBlock Margin="8,0,0,0" Text="AddressLine2" FontSize="16" Foreground="White" HorizontalAlignment="Left" Width="146"/> 
     <TextBox x:Name="inputAddressLine2" TextWrapping="Wrap" Margin="219,0,0,0"/> 
    </Grid> 
    <Grid Height="30" Margin="8,0,8,7" VerticalAlignment="Bottom" Grid.Row="1"> 
     <TextBlock Margin="8,0,0,0" Text="Post Code" FontSize="16" Foreground="White" HorizontalAlignment="Left" Width="107"/> 
     <TextBox x:Name="inputPostCode" TextWrapping="Wrap" Margin="219,0,0,0"/> 
    </Grid> 
    <Grid Height="30" VerticalAlignment="Bottom" Margin="8,0,8,9" Grid.Row="4"> 
     <TextBox x:Name="inputCounty" TextWrapping="Wrap" Margin="220,0,0,0"/> 
     <TextBlock Margin="8,0,0,0" Text="County" FontSize="16" Foreground="White" HorizontalAlignment="Left" Width="155"/> 
    </Grid> 
    <Grid Margin="8,8,8,5" Grid.Row="3"> 
     <TextBox x:Name="inputTown" TextWrapping="Wrap" Margin="219,0,0,0"/> 
     <TextBlock Margin="8,0,0,0" Text="AddressLine2" FontSize="16" Foreground="White" HorizontalAlignment="Left" Width="165"/> 
    </Grid> 
    <Grid Margin="8" Grid.Row="5"> 
     <TextBlock Text="Number" FontSize="16" Foreground="White" Margin="8,0,0,0" HorizontalAlignment="Left" Width="178"/> 
     <TextBox x:Name="inputNumber" TextWrapping="Wrap" Margin="220,0,0,0"/> 
    </Grid> 
</Grid> 

Encore que cela se remonter d'un niveau profond, retour 6 grilles et un bouton!

Ma fonction actuelle de Traverse est:

public static IEnumerable<UIElement> Traverse(this UIElementCollection source) 
    { 
     source.OfType<Grid>().SelectMany(v => Traverse(v.Children)); 
     //This is the top level. 
     foreach (UIElement item in source) 
     { 
      yield return item; 
     } 
    } 

Ce sait juste que nous traitons avec des grilles donc pas besoin pour le second argument. Je cède seulement de la boîte de l'itérateur, pas de la première ligne qui devrait rappeler dans la fonction Traverse avec les grilles de l'enfant.

Répondre

3

Voici la fonction que j'utilise pour livrer ce genre de chose: -

public static IEnumerable<DependencyObject> Descendents(this DependencyObject root) 
    { 
     int count = VisualTreeHelper.GetChildrenCount(root); 
     for (int i = 0; i < count; i++) 
     { 
      var child = VisualTreeHelper.GetChild(root, i); 
      yield return child; 
      foreach (var descendent in Descendents(child)) 
       yield return descendent; 
     } 
    } 

Avec cette méthode d'extension disponible votre code devient: -

foreach(var txt in baseLayout.Descendents().OfType<TextBox>()) 
{ 
    txt.reset(); 
} 

Notez éviter un "foreach" méthode d'extension est l'un de choix. Je n'aime pas l'idée d'une méthode d'extension LINQEsq en train de muter ou de faire quoi que ce soit pour l'application. Je préfère utiliser un foreach pour réellement fonctionner alors sur les résultats de la requête.

Modifier pour la "Méthode d'extension junkies" (si votre logique vous ne faire): -

public static IEnumerable<T> ForEach(this IEnumerable<T> items, Action<T> fn) 
{ 
    foreach (T item in items) 
     fn(item); 
} 

Modifier quel est le problème avec votre code.

bien avant cette ligne profonde dans votre méthode Traverse est la principale cause de votre problème: -

t.Traverse(fnRecurse); 

Il returnns un IEnumerable<UIElement> mais vous ne font rien avec elle, pas même stocker le résultat dans un variable.

cette ligne aussi: -

var g = source.OfType<Grid>(); 

provoquerait chaque grille trouve à énumérait, pour chaque UIElement trouvé. Ainsi, par exemple, si la source contient un TextBox et 2 Grids, la ligne ci-dessus est appelée 3 fois. Les deux Grids seraient parcourus à travers le foreach deux fois.

cette ligne aussi: -

yield return itemsub; 

bien itemsub est toujours un Grid et sera filtré par la TypeOf<TextBox> ultérieure.

Par conséquent, le seul TextBox que ce code retournerait est n'importe quel TextBox trouvé dans le UIElementCollection initial.

+0

Anthony, je suis un accro de la méthode d'extension, d'où mon ForEach! Bien sûr, cela ne me laisse pas utiliser le rendement. Ta pour le code, je vais le monter mais je vais éviter la tique pendant un certain temps en cas d'une méthode d'extension pure arrive! – DavidA

+0

votre méthode fonctionne, pas la mienne. C'est la fin de la journée ... J'ai besoin de savoir pourquoi :) – DavidA

+0

@DavidA: J'ai ajouté un ForEach pour vous, malgré ce que je ressens à ce sujet (croyez-moi c'est vraiment une mauvaise idée). Cela m'aiderait à vous décrire pourquoi votre code d'origine ne fonctionne pas si a) vous montrez votre méthode d'extension ForEach et b) un échantillon de XAML étant répété. – AnthonyWJones

Questions connexes