Ricerca di controllo ricorsiva con LINQ
-
05-07-2019 - |
Domanda
Se volessi trovare le caselle di controllo selezionate su una pagina ASP.NET potrei usare la seguente query LINQ.
var checkBoxes = this.Controls
.OfType<CheckBox>()
.TakeWhile<CheckBox>(cb => cb.Checked);
Funziona bene se le caselle di controllo sono nidificate nella raccolta di controlli corrente, ma mi piacerebbe sapere come estendere la ricerca eseguendo il drill-down nelle raccolte di controlli dei controlli di livello superiore.
La domanda è stata posta qui:
Ricerca di controlli che utilizzano una determinata interfaccia in ASP.NET
E ho ricevuto risposte non LINQ, ho già la mia versione di una ricerca di controllo ricorsivo su tipo e ID come metodi di estensione, ma mi chiedevo solo quanto sia facile farlo in LINQ?
Soluzione
Prendi il tipo / ID controllando la ricorsione, quindi basta avere un " dammi tutti i controlli, ricorsivamente " metodo, ad esempio
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;
}
}
}
È un po 'inefficiente (in termini di creazione di molti iteratori) ma dubito che avrai un albero molto profondo .
È quindi possibile scrivere la query originale come:
var checkBoxes = this.GetAllControls()
.OfType<CheckBox>()
.TakeWhile<CheckBox>(cb => cb.Checked);
(EDIT: ha cambiato AllControls in GetAllControls e lo usa correttamente come metodo.)
Altri suggerimenti
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;
}
Ora in base alla funzione sopra, possiamo fare qualcosa del genere:
public static Control FindControl(this Control container, string Id)
{
var child = container.AllControls().FirstOrDefault(c => c.ID == Id);
return child;
}
Il mio suggerimento per rendere ricorsivo il 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;
}
}
Il secondo foreach
sembra strano, ma questo è l'unico modo che conosco per "appiattire" la chiamata ricorsiva.