Поиск рекурсивного контроля с помощью LINQ - PullRequest
34 голосов
/ 31 октября 2008

Если бы я хотел найти отмеченные флажки на странице ASP.NET, я мог бы использовать следующий запрос LINQ.

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

Это прекрасно работает, если флажки вложены в текущую коллекцию элементов управления, но я хотел бы знать, как расширить поиск, углубившись в наборы элементов управления элементов верхнего уровня.

Вопрос был задан здесь:

Поиск элементов управления, которые используют определенный интерфейс в ASP.NET

И, получив ответы, не относящиеся к LINQ, у меня уже есть собственная версия рекурсивного поиска по типу и идентификатору в качестве методов расширения, но я просто удивился, насколько легко это сделать в LINQ?

Ответы [ 3 ]

44 голосов
/ 31 октября 2008

Возьмите проверку типа / идентификатора из рекурсии, так что просто используйте метод "дай мне все элементы управления, рекурсивно", например

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 и использовать его как метод.)

2 голосов
/ 03 марта 2011
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;
}
0 голосов
/ 31 октября 2008

Мое предложение сделать 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 выглядит странно, но я знаю, что это единственный способ "сгладить" рекурсивный вызов.

...