Recuperer l'instance d'un control à partir de son clientid

Soyez le premier à donner votre avis sur cette source.

Snippet vu 18 568 fois - Téléchargée 28 fois

Contenu du snippet

Asp.net donne la possibilité de créer des ID "unique" pour les contrôles clients, il s'agit du ClientID du contrôle. Cet ID est généré en concatenant le ClientID du contrôle parent et de l'ID du contrôle.

Dans un de mes projets, j'avais besoin de récuperer le Control en ayant seulement son ClientID, voici donc une méthode qui rempli ce rôle :-)

Attention pour que cette source fonctionne il faut impérativement que l'arbre de contrôle soit créer c'est à dire qu'on doit obligatoirement appeller cette méthode aprés le page_init ...

C'est une fonction récursive, vous devez obligatoirement passer l'objet Page en premier paramètre

Source / Exemple :


/// <summary>
        /// Stock the ClientID of the control to find 
        /// </summary>
        private static String _clientID;

        /// <summary>
        /// Obtain a control from the ClientID
        /// </summary>
        /// <param name="page">You must pass the Page here</param>
        /// <param name="ClientID">the ClientID of the control you search</param>
        /// <returns>the Control matching the clientID, if not found return null</returns>
        /// <example>
        /// Control c = Utils.getControlsFromClientID(Page, "Panel1_Lbl1");
        /// </example>
        /// <remarks>Must be called after the page_init, before the tree of Control isn't construct</remarks>
        internal static Control getControlFromClientID(Page page, String ClientID)
        {
            _clientID = ClientID;

            Control c = page.FindControl(ClientID);
            if (c != null)
                return c;

            return getControlFromClientIDInternal(page);
        }

        /// <summary> 
        /// Obtain a control from a container 
        /// </summary> 
        /// <param name="Container"></param> 
        /// <returns>use recursivity</returns> 
        /// <remarks>the _clientID params is extern to not put into stack the value each call : better performance</remarks> 
        private static Control getControlFromClientIDInternal(Control Container)
        {
            Control c;
            if (_clientID.Length > Container.ClientID.Length)
            {
                c = Container.FindControl(_clientID.Remove(0, Container.ClientID.Length + 1));
                if (c != null)
                    return c;
            }
            foreach (Control child in Container.Controls)
            {
                if (child.Controls.Count > 0)
                {
                    c = getControlFromClientIDInternal(child);
                    if (c != null)
                    {
                        _clientID = string.Empty;
                        return c;
                    }
                }
            }
            return null;
        }

Conclusion :


Je crois avoir géré la plupart des cas, mais si vous trouver un bug merci de le signaler ;-)

A voir également

Ajouter un commentaire Commentaires
hugonjerome Messages postés 1 Date d'inscription mardi 18 octobre 2005 Statut Membre Dernière intervention 21 octobre 2008
21 oct. 2008 à 16:31
Salut,

J'ai ajouté une condition avant de renvoyer le contrôle trouvé pour vérifier que le ClientID du control trouvé est identique à celui cherché, j'ai rencontré le problème dans le cas d'un repeater où le contrôle renvoyé était toujours le premier, j'ai également modifié les métodes pour ne plus utiliser l'attribut static ni de string '_clientid':


private Control getControlFromClientID(Page page, string ClientID)
{
Control c = page.FindControl(ClientID);
if (c != null)
return c;
return getControlFromClientIDInternal(page, ClientID);
}
private Control getControlFromClientIDInternal(Control Container, string ClientID)
{
Control c;
if (ClientID.Length > Container.ClientID.Length)
{
c = Container.FindControl(ClientID.Remove(0, Container.ClientID.Length + 1));
if (c != null)
if (c.ClientID == ClientID)
return c;
}
foreach (Control child in Container.Controls)
{
if (child.Controls.Count > 0)
{
c = getControlFromClientIDInternal(child, ClientID);
if (c != null)
if (c.ClientID == ClientID)
{
ClientID = string.Empty;
return c;
}
}
}
return null;
}

J'utilise ce code pour rechercher des contrôles dans une page ayant une master page et sachant que le contrôle est inclus dans deux repeater imbriqués.

++
fcruveillier Messages postés 1 Date d'inscription vendredi 26 octobre 2007 Statut Membre Dernière intervention 21 décembre 2007
21 déc. 2007 à 11:19
Hello,
Je suis tombée sur un cas qui pose un problème (en vb.Net en tout cas):
- la CheckBoxList.

En effet, lorsque dans le processus de recherche d'un contrôle, "il" tombe sur une CBL, il effectue le getControlFromClientIDInternal, puisque que la CBL contient des CheckBox.

Et c'est là qu'il y a à mon avis un Bug(un bug vb j'entends!), car dans ce cas, la ligne
c = Container.FindControl(_clientID.Remove(0, Container.ClientID.Length + 1));
renvoie TOUJOURS la CheckBoxList en question !
j'ai même essayé dans la trace de mettre c = Container.FindControl("toto"), ça marche aussi !!...

j'ai donc ajouté une condition:

if (_clientID.Length > Container.ClientID.Length)
{
-> if (Container.GetType().ToString() != "System.Web.UI.WebControls.CheckBoxList" )
{
c = Container.FindControl(_clientID.Remove(0, Container.ClientID.Length + 1));
if (c != null)
return c;
}
// else:
// {
// ici il faut gérer la recherche des checkbox d'une CBL, si c'est nécessaire
// (avec un for each je pense)
// }
}

En espérant avoir aidé quelqu'un...
Mais peut-être quelqu'un a une meilleure idée pour gérer ce cas !

@Plus :o)
cs_Yopyop Messages postés 586 Date d'inscription lundi 7 janvier 2002 Statut Membre Dernière intervention 10 février 2010 1
6 juil. 2006 à 13:38
oki, donc environs 5000 contrôles...

tiens moi au courant pour la mémoire, ca m'intéresse énormément.

yopyop
jesusonline Messages postés 6814 Date d'inscription dimanche 15 décembre 2002 Statut Membre Dernière intervention 13 octobre 2010 29
6 juil. 2006 à 13:06
oui ta méthode est tout de même interessante niveau algo ;-)

pour ce qui est de ma page de test, je devais avoir une centaine de label dans un UC et une 50aine d'UC dans la page ...

Donc une trés grosse page :)

pour les temps, c'etait autour de 0,000150s pour ma méthode et 0,000800s pour ta méthode (en mode debug en plus) ... donc on essaye d'optimiser pour pas grand chose :-)

Le passage du _clientID est surement l'une des solutions que je vais adopter :p En ce qui concerne la mémoire utilisé, je vais essayer de trouver une astuce pour pouvoir comparer ca, car ca m'interesse :-)
cs_Yopyop Messages postés 586 Date d'inscription lundi 7 janvier 2002 Statut Membre Dernière intervention 10 février 2010 1
6 juil. 2006 à 12:57
yop,

effectivement, je n'ai pas tout testé.

Mais il me semble que les les contrôles doivent toujours être dans entre les balises form.
Autrement, pour partir de la page directement il suffit de ne pas utiliser l'instruction
form = FindFormControl(page); (mettre form=Page devrait enlever le bug).

Concernant la rapidité, je peux certainement améliorer ca (mais g pas le temps pour l'instant, surtout de créer la page de test. Environs combien de contrôles ? 5 fois plus rapide, mais genre on passe de 1 à 5 secondes ou de 0.1 seconde à 0.5 ?).

bref ... j'ai au moins montré comment parcourir un arbre sans récursivité, ce qui à mon avis est intéressant ... non ?

Concernant ton static, pourquoi ne passes-tu pas le ClientID en paramètre ?
private static Control getControlFromClientIDInternal(Control Container, ref String ClientId)
(je ne connais pas l'équivalent de ByRef en C#).
Avec ca ta variable n'est pas copiée en mémoire (juste la référence).

Concernant la mémoire sur le serveur, tout dépend de la fréquentation de ton application.
Sur les gros sites ca peut causer de gros problèmes (je prèfère ajouter 2-3 secondes de loading sur une page plutôt que d'empêcher 500 personnes de bosser pendant 30 minutes).

yopyop

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.