Pergunta

Se eu quisesse encontrar caixas de seleção verificados em uma página ASP.NET que eu poderia usar a seguinte consulta LINQ.

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

Esta coima funciona se as caixas estão aninhadas na coleção de controle atual, mas eu gostaria de saber como estender a busca por perfuração para baixo nas coleções dos controles de nível superior de controle.

A pergunta foi feita aqui:

Encontrar controles que usam uma determinada interface no ASP.NET

E recebeu respostas não-LINQ, eu já tenho minha própria versão de uma pesquisa de controle recursiva do tipo e ID como métodos de extensão, mas eu só queria saber como isso é fácil de fazer em LINQ?

Foi útil?

Solução

Leve o tipo / ID check-out do recursividade, portanto basta ter um "me dê todos os controles, de forma recursiva" método de, e.

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

Isso é um tanto ineficiente (em termos de criação de lotes de iteradores), mas eu duvido que você vai ter um muito árvore de profundidade.

Você pode então escrever sua consulta original como:

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

(EDIT:. AllControls alterado para GetAllControls e usá-lo corretamente como um método)

Outras dicas

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

Agora baseada na função acima, podemos fazer algo como isto:

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

A minha sugestão para tornar o recursiva 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;
        }
    }

O segundo foreach parece estranho, mas esta é a única forma que conheço para "aplainar" a chamada recursiva.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top