web-dev-qa-db-fra.com

Obtenir tous les contrôles Web d'un type spécifique sur une page

Je me demandais comment obtenir tous les contrôles sur une page, puis effectuer une tâche sur eux dans cette question connexe:

Comment effectuer une recherche par programme dans DropDownList C #

J'ai besoin d'un code qui peut numériser la page, obtenir tous les contrôles DropDownList et les renvoyer dans une liste.

Je suis actuellement en train de modifier chaque contrôle, je préférerais pouvoir passer en boucle de manière dynamique sur chaque contrôle pour préformer ma tâche.

31
Anicho

Vérifiez ma précédente SO réponse .

En gros, l’idée est d’envelopper la récurrence d’itération dans la collection de contrôles en utilisant:

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

et de l'utiliser:

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

[Modifié le 26/11/2013]: voici un moyen plus élégant d'atteindre cet objectif. J'ai écrit deux méthodes d'extensions qui peuvent parcourir l'arbre de contrôle dans les deux sens. Les méthodes sont écrites de manière plus Linq car elles produisent un énumérable:

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

Grâce au mot clé this, ces méthodes sont des méthodes d'extensions et peuvent simplifier le code.

Par exemple, pour trouver tous les DropDownList dans la page, vous pouvez simplement appeler:

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

En raison de l'utilisation du mot clé yield et du fait que Linq est suffisamment intelligent pour différer l'exécution de l'énumération, vous pouvez appeler (par exemple):

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

L'énumération s'arrêtera dès que le prédicat de la méthode First sera satisfait. Tout l'arbre de contrôle ne sera pas parcouru.

57
Steve B
foreach (DropDownList dr in this.Page.Form.Controls.OfType<DropDownList>())
{

}
15
marko

Si j'avais eu cette question et bien que j'ai trouvé la réponse de Steve B utile, je voulais une méthode d'extension, donc reformulez-la:

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

Voici une version récursive qui renvoie une collection de contrôles du type demandé au lieu d'utiliser un autre argument:

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

Insérer dans votre classe (statique optionnelle).

5
Greg Searle

Vous pouvez utiliser la logique récursive pour obtenir tous les contrôles, comme ceci:

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);
    }
}
1
James Johnson

Faire une boucle entre les contrôles d’une page n’est pas difficile; il vous suffit de regarder dans chaque contrôle pour obtenir plus de contrôles.

Vous pourriez faire quelque chose comme

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

Cela fonctionne si vous utilisez les composants de formulaire de system.web.ui Cependant, cela ne fonctionne pas lorsque vous les utilisez depuis system.web.mvc apparemment, donc j’ai proposé le travail suivant.

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/>");
                        }

                    }

Cela fonctionne pour moi, mais j'ai découvert que le bouton radio, s'il n'est pas sélectionné, est nul, donc ne renvoie rien, ce qui est correct. Je n'ai pas à écrire quoi que ce soit dans la base de données si elle est nulle. 

0
Frederik van Vliet
        var dropDownLists = new List<DropDownList>();
        foreach (var control in this.Controls)
        {
            if (control is DropDownList)
            {
                dropDownLists.Add( (DropDownList)control );
            }
        }
0
dudeNumber4