2

Silverlight ページのすべてのテキスト ボックスをトラバースするための拡張メソッドが必要です。常にグリッド レイアウトを使用すると仮定すると、次のようになります。

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;

                };
        }

    }

これで、次のように呼び出すことができます。

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

これは決して発火しません。UI要素を区別できないのはOfTypeだと思います。

どうすればいいですか?ビジュアル ツリーをフラット化し、循環させたいと考えています。テキストボックスだけでなく、必要なものをすべて取得するだけです。譲歩する場所が間違っているか、それとも頻繁に譲歩していませんか?

編集:

現在のコード

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

    }

そしてグリッドは

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

6 つのグリッドと 1 つのボタンを返すと、まだ 1 レベルの深さしかありません!

私の現在のトラバース機能は次のとおりです。

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

これは、グリッドを扱っていることを知っているだけなので、2 番目の引数は必要ありません。子グリッドを使用して Traverse 関数にコールバックする必要がある最初の行からではなく、イテレータ ボックスからのみ生成します。

4

1 に答える 1

3

この種のものを提供するために私が使用する関数は次のとおりです:-

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

その拡張メソッドを使用すると、コードは次のようになります。

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

「foreach」拡張メソッドの回避は選択の 1 つです。LINQEsq 拡張メソッドが実際に変更したり、アプリケーションに対して何かを実行したりするという考えは好きではありません。foreach私は実際に適切なを使用して、クエリの結果を操作することを好みます。

「拡張メソッドジャンキー」のために編集します(賢明な場合はこれを行いません):-

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

コードの問題点を編集します。

主に Traverse メソッドの奥深くにあるこの行が問題の主な原因です:-

 t.Traverse(fnRecurse);

を返しIEnumerable<UIElement>ますが、結果を変数に格納することさえせず、何もしません。

また、この行: -

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

見つかった各 UIElement に対して、見つかった各グリッドが列挙されます。たとえば、ソースに TextBox と 2 つのグリッドが含まれている場合、上記の行は 3 回呼び出されます。両方のグリッドが内側foreachを 2 回通過します。

また、この行: -

yield return itemsub;

itemsub は常に でGridあり、後続の によって除外されTypeOf<TextBox>ます。

したがって、このコードが返す唯一の TextBox は、 initial で見つかった TextBoxUIElementCollectionです。

于 2010-01-26T16:13:53.883 に答える