2011-09-09 7 views
27

he estado pensando cómo puedo conseguir todos los controles en una página y luego realizar una tarea en ellos en esta pregunta relacionada:Obtener todos los controles Web de un tipo específico en una página

How to Search Through a C# DropDownList Programmatically

Necesito código que puede escanear la página, obtener todos los controles DropDownList y devolverlos en una lista.

Actualmente estoy teniendo que editar cada control individual, preferiría poder hacer un bucle dinámico sobre cada control para realizar mi tarea.

Respuesta

50

Comprobar my previous SO answer.

Básicamente, la idea es envolver la recursividad de iteración a través de la colección de controles usando:

private void GetControlList<T>(ControlCollection controlCollection, List<T> resultCollection) 
where T : Control 
{ 
    foreach (Control control in controlCollection) 
    { 
     //if (control.GetType() == typeof(T)) 
     if (control is T) // This is cleaner 
      resultCollection.Add((T)control); 

     if (control.HasControls()) 
      GetControlList(control.Controls, resultCollection); 
    } 
} 

y utilizarlo:

List<DropDownList> allControls = new List<DropDownList>(); 
GetControlList<DropDownList>(Page.Controls, allControls) 
foreach (var childControl in allControls) 
{ 
//  call for all controls of the page 
} 

[Editado 26/11/2013] : aquí hay una forma más elegante de alcanzar este objetivo. Escribí dos métodos de extensiones que pueden recorrer el árbol de control en ambas direcciones. Los métodos se escriben de una manera más LINQ, ya que produce un enumerable:

/// <summary> 
/// Provide utilities methods related to <see cref="Control"/> objects 
/// </summary> 
public static class ControlUtilities 
{ 
    /// <summary> 
    /// Find the first ancestor of the selected control in the control tree 
    /// </summary> 
    /// <typeparam name="TControl">Type of the ancestor to look for</typeparam> 
    /// <param name="control">The control to look for its ancestors</param> 
    /// <returns>The first ancestor of the specified type, or null if no ancestor is found.</returns> 
    public static TControl FindAncestor<TControl>(this Control control) where TControl : Control 
    { 
     if (control == null) throw new ArgumentNullException("control"); 

     Control parent = control; 
     do 
     { 
      parent = parent.Parent; 
      var candidate = parent as TControl; 
      if (candidate != null) 
      { 
       return candidate; 
      } 
     } while (parent != null); 
     return null; 
    } 

    /// <summary> 
    /// Finds all descendants of a certain type of the specified control. 
    /// </summary> 
    /// <typeparam name="TControl">The type of descendant controls to look for.</typeparam> 
    /// <param name="parent">The parent control where to look into.</param> 
    /// <returns>All corresponding descendants</returns> 
    public static IEnumerable<TControl> FindDescendants<TControl>(this Control parent) where TControl : Control 
    { 
     if (parent == null) throw new ArgumentNullException("control"); 

     if (parent.HasControls()) 
     { 
      foreach (Control childControl in parent.Controls) 
      { 
       var candidate = childControl as TControl; 
       if (candidate != null) yield return candidate; 

       foreach (var nextLevel in FindDescendants<TControl>(childControl)) 
       { 
        yield return nextLevel; 
       } 
      } 
     } 
    } 
} 

Gracias a la palabra clave this, estos métodos son métodos de extensiones y pueden simplificar el código.

Por ejemplo, para encontrar todos DropDownList en la página, sólo tiene que llamar:

var allDropDowns = this.Page.FindControl<DropDownList>(); 

Debido a la utilización de la palabra clave yield, y debido a LINQ es lo suficientemente inteligente como para aplazar la ejecución de la enumeración, se puede llamar a (por ejemplo):

var allDropDowns = this.Page.FindDescendants<DropDownList>(); 
var firstDropDownWithCustomClass = allDropDowns.First(
    ddl=>ddl.CssClass == "customclass" 
    ); 

la enumeración se detendrá tan pronto como el predicado en el método First está satisfecho. El árbol de control completo no será caminado.

+1

La respuesta más completa y funciona como un amuleto de aclamaciones. – Anicho

+0

http://msdn.microsoft.com/en-us/library/yt340bh4.aspx Buen artículo sobre msdn está bien. – Anicho

+0

Me gusta. Es bueno que ya no necesite usar una palabra clave yield, lo que hizo que la función recursiva siempre se ejecutara aunque declaré que Visual Studio la pisó. – JonathanWolfson

0
 var dropDownLists = new List<DropDownList>(); 
     foreach (var control in this.Controls) 
     { 
      if (control is DropDownList) 
      { 
       dropDownLists.Add((DropDownList)control); 
      } 
     } 
+7

estoy bastante seguro que necesitas recurse. – SLaks

2

El bucle a través de los controles en una página no es difícil; solo tiene que mirar dentro de cada control para obtener más controles.

Se podría hacer algo como

foreach(var control in Page) 
{ 
    if(control is DropDownList) 
    { 
     //Do whatever 
    } 
    else 
    { 
     //Call this function again to search for controls within this control 
    } 
} 
+2

Esto no funcionará. Necesita ser recursivo –

+2

Para eso está el resto ... // Llamar de nuevo a esta función para buscar controles dentro de este control ... eso requiere algo recurisve ... –

1

Puede usar la lógica recursiva para obtener todos los controles, así:

private void PopulateSelectList(Control parentCtrl, List<DropDownList> selectList) 
{ 
    foreach (Control ctrl in parentCtrl.Controls) 
    { 
     if (ctrl is DropDownList) 
     { 
      selectList.Add(((DropDownList)ctrl); 
      continue; 
     } 
     FindAllControls(ctrl, selectList); 
    } 
} 
14
foreach (DropDownList dr in this.Page.Form.Controls.OfType<DropDownList>()) 
{ 

} 
+0

uno con la menor cantidad de código de la misma cosa xD – Anicho

+2

Para que esto funcione correctamente, debe ser recursivo. –

+0

¡Sí! Necesita iterar cada control Controles de recopilación: recursividad. Pero creo que estos métodos de extensión son realmente útiles porque hacen que su código sea más compacto: más trabajo en menos líneas. – marko

5

tenido esta misma pregunta y al mismo tiempo me encontré con la respuesta de Steve B útil, que querían un método de extensión, por lo que re-factorizado que:

public static IEnumerable<T> GetControlList<T>(this ControlCollection controlCollection) where T : Control 
    { 
     foreach (Control control in controlCollection) 
     { 
      if (control is T) 
      { 
       yield return (T)control; 
      } 

      if (control.HasControls()) 
      { 
       foreach (T childControl in control.Controls.GetControlList<T>()) 
       { 
        yield return childControl; 
       } 
      } 
     } 
    } 
+0

Recibo un error de intelli-sense en "this" diciendo "Tipo esperado". Simplemente estoy agregando esto a una clase en la carpeta app_code. – Fandango68

4

Aquí está una versión recursiva que devuelve una colección de controles de el tipo solicitado en lugar de utilizar otro argumento:

using System.Collections.Generic; 
using System.Web.UI; 
// ... 
public static List<T> GetControls<T>(ControlCollection Controls) 
where T : Control { 
    List<T> results = new List<T>(); 
    foreach (Control c in Controls) { 
    if (c is T) results.Add((T)c); 
    if (c.HasControls()) results.AddRange(GetControls<T>(c.Controls)); 
    } 
    return results; 
} 

Inserte en su clase (estática opcional).

0

Esto funciona si utiliza los componentes de formulario de system.web.ui , pero esto no funciona cuando los utiliza desde system.web.mvc aparentemente, así que se me ocurrió lo siguiente.

for (Int32 idx = 0; idx < formCollection.Count; idx += 1) 
        { 
        String Name = formCollection.Keys[idx]; 
        String value = formCollection[idx]; 

        if (Name.Substring(0, 3).ToLower() == "chk") 

         { 
         Response.Write(Name + " is a checkbox <br/>"); 
         } 
        else if (Name.Substring(0, 5).ToLower() == "txtar") 
         { 
         Response.Write(Name + " is a text area <br/>"); 
         } 
        else if (Name.Substring(0, 2).ToLower() == "rd") 
         { 
         Response.Write(Name + " is a RadioButton <br/>"); 
         } 

        } 

Esto funciona para mí, sin embargo descubrí que botón de radio si no se ha seleccionado es nulo por lo que duerma devuelve nada, que está bien no tengo que escribir nada en la base de datos si es nula

Cuestiones relacionadas