2008-10-31 17 views
33

Si quisiera encontrar casillas de verificación marcadas en una página ASP.NET, podría usar la siguiente consulta LINQ.Búsqueda de control recursivo con LINQ

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

que funciona bien si las casillas de verificación están anidados en la colección de controles actual, pero me gustaría saber cómo ampliar la búsqueda mediante la profundización en las colecciones de control de los controles de nivel superior.

La pregunta fue hecha aquí:

Finding controls that use a certain interface in ASP.NET

y recibió respuestas no LINQ, ya tengo mi propia versión de una búsqueda de control recursivo del tipo y la identificación que los métodos de extensión, pero me preguntaba cómo fácil esto es hacer en LINQ?

Respuesta

43

Realice la comprobación de tipo/ID fuera de la recursión, por lo que solo tiene que utilizar el método "darme todos los controles recursivamente", p.

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

Eso es algo ineficaz (en términos de crear un montón de iteradores) pero dudo que vas a tener un árbol de profundidad muy .

A continuación, puede escribir su búsqueda original como:

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

(EDIT:. Cambiado AllControls a GetAllControls y utilizarlo adecuadamente como método)

+0

que funciona, pero si estuviera usando los controles de terceros y sus propios controles de servidor como lo hacemos en mi lugar de trabajo actual , puedes obtener unos buenos niveles de anidación de control. Supongo que una página ASP.NET es solo un ejemplo de un problema más general, el de profundizar en colecciones anidadas en Linq. – PhilGriffin

+0

He usado solo esta técnica antes. (Si quieres ser realmente dulce, ¡podrías hacer esto como una expresión con el Y Combinator!) ¿Por cierto, no se debe usar AllControls como método? – yfeldblum

+1

@Phil: Sí, puede bajar algunos niveles y ser un poco ineficiente, pero ¿tiene alguna razón para creer que será un * cuello de botella * significativo? Haga lo más simple que funciona primero, y luego optimice si realmente es un problema. (Por ejemplo, una sola llamada a una base de datos puede abrumar este costo). –

0

Mi sugerencia para hacer que el recursiva AllControls es:

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

el segundo foreach ve raro, pero esta es la única forma que conozco para "aplanar" la llamada recursiva.

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

ahora se basa en la función anterior, podemos hacer algo como esto:

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