37

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

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

如果复选框嵌套在当前控件集合中,那效果很好,但我想知道如何通过深入到顶级控件的控件集合来扩展搜索。

问题在这里被问到:

在 ASP.NET 中查找使用特定接口的控件

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

4

3 回答 3

47

从递归中检查类型/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 并正确使用它作为一种方法。)

于 2008-10-31T15:43:57.823 回答
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;
}
于 2011-03-03T19:08:28.323 回答
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看起来很奇怪,但这是我知道“扁平化”递归调用的唯一方法。

于 2008-10-31T16:10:53.433 回答