【问题标题】:Recursive silverlight Element finder extension method递归silverlight Element finder扩展方法
【发布时间】:2011-01-09 13:10:22
【问题描述】:

我需要一个扩展方法来遍历我的 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();
                });

这永远不会触发。我相信是 OfType 无法区分 UI 元素。

我该怎么做?我想展平视觉树然后循环。不仅仅是文本框,而是得到所有我想要的东西。我是在错误的地方屈服还是过于频繁?

编辑:

当前代码

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 个网格和一个按钮!

我目前的遍历函数是:

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

这只是知道我们正在处理网格,因此不需要第二个参数。我只是从迭代器框中产生,而不是从应该回调到带有子网格的 Traverse 函数的第一行。

【问题讨论】:

    标签: silverlight recursion methods yield


    【解决方案1】:

    这是我用来交付这类东西的函数:-

        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”扩展方法是一种选择。我不喜欢 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&lt;UIElement&gt;,但你不使用它做任何事情,甚至不将结果存储在变量中。

    还有这一行:-

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

    将导致每个找到的网格被枚举,对于找到的每个 UIElement。因此,例如,如果源包含一个 TextBox 和 2 个网格,则上面的行被调用 3 次。两个网格都将通过内部foreach 运行两次。

    还有这一行:-

    yield return itemsub;
    

    well itemsub 始终是Grid,会被后面的TypeOf&lt;TextBox&gt; 过滤掉。

    因此,此代码将返回的唯一 TextBox 是在初始 UIElementCollection 中找到的任何 TextBox。

    【讨论】:

    • Anthony,我是扩展方法迷,因此我的 ForEach!当然,这不允许我使用产量。 Ta 的代码,我会升级它,但我会暂时避免打勾,以防出现纯扩展方法!
    • 你的方法有效,我的无效。这是一天的结束......我需要知道为什么:)
    • @DavidA:我已经为你添加了一个 ForEach,尽管我感觉如何(相信我,这确实是个坏主意)。如果 a) 你展示你的 ForEach 扩展方法和 b) XAML 的样本被迭代,这将帮助我向你描述为什么你的原始代码不起作用。
    • 我有我的 ForEach!粉笔和奶酪。我已经习惯了 jquery,所以它看起来很自然。
    • 我使用和你一样的 foreach。我有一个包含 6 个嵌套网格的网格,每个网格包含一个文本块和一个文本框。我能收集到的,我不是递归的,Traverse 函数只返回前 6 个网格。
    猜你喜欢
    • 1970-01-01
    • 2015-08-28
    • 1970-01-01
    • 2018-04-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-04
    • 2013-02-11
    相关资源
    最近更新 更多