使用LINQ进行递归控制搜索

时间:2008-10-31 15:37:34

标签: asp.net .net-3.5 c#-3.0 linq-to-objects

如果我想在ASP.NET页面上找到选中的复选框,我可以使用以下LINQ查询。

var checkBoxes = this.Controls
                     .OfType<CheckBox>()
                     .TakeWhile<CheckBox>(cb => cb.Checked);

如果复选框嵌套在当前控件集合中,那么工作正常,但我想知道如何通过向下钻取到顶级控件的控件集合来扩展搜索。

这里提出的问题是:

Finding controls that use a certain interface in ASP.NET

并且收到了非LINQ答案,我已经有自己的类型和ID作为扩展方法的递归控件搜索版本,但我只是想知道在LINQ中这样做有多容易吗?

3 个答案:

答案 0 :(得分:44)

从递归中取出类型/ ID检查,所以只需要“给我所有控件,递归”方法,例如

public static IEnumerable<Control> GetAllControls(this Control parent)
{
    foreach (Control control in parent.Controls)
    {
        yield return control;
        foreach(Control descendant in control.GetAllControls())
        {
            yield return descendant;
        }
    }
}

这有点效率低(在创建大量迭代器方面)但我怀疑你会有一个非常深度树。

然后您可以将原始查询编写为:

var checkBoxes = this.GetAllControls()
                     .OfType<CheckBox>()
                     .TakeWhile<CheckBox>(cb => cb.Checked);

(编辑:将AllControls更改为GetAllControls并正确使用它作为方法。)

答案 1 :(得分:2)

public static IEnumerable<Control> AllControls(this Control container)
{
    //Get all controls
    var controls = container.Controls.Cast<Control>();

    //Get all children
    var children = controls.Select(c => c.AllControls());

    //combine controls and children
    var firstGen = controls.Concat(children.SelectMany(b => b));

    return firstGen;
}

现在基于上述功能,我们可以这样做:

public static Control FindControl(this Control container, string Id)
{
    var child = container.AllControls().FirstOrDefault(c => c.ID == Id);
    return child;
}

答案 2 :(得分:0)

我建议AllControls递归:

    public static IEnumerable<Control> AllControls(this Control parent)
    {
        foreach (Control control in parent.Controls)
        {
             yield return control;
        }
        foreach (Control control in parent.Controls)
        {
            foreach (Control cc in AllControls(control)) yield return cc;
        }
    }

第二个foreach看起来很奇怪,但这是我知道“压扁”递归调用的唯一方法。