Pesquisa controle recursivo com LINQ
-
05-07-2019 - |
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?
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.