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

Soyez le premier à donner votre avis sur cette source.

Snippet vu 18 162 fois - Téléchargée 26 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

Messages postés
1
Date d'inscription
mardi 18 octobre 2005
Statut
Membre
Dernière intervention
21 octobre 2008

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.

++
Messages postés
1
Date d'inscription
vendredi 26 octobre 2007
Statut
Membre
Dernière intervention
21 décembre 2007

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)
Messages postés
586
Date d'inscription
lundi 7 janvier 2002
Statut
Membre
Dernière intervention
10 février 2010
1
oki, donc environs 5000 contrôles...

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

yopyop
Messages postés
6814
Date d'inscription
dimanche 15 décembre 2002
Statut
Modérateur
Dernière intervention
13 octobre 2010
23
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 :-)
Messages postés
586
Date d'inscription
lundi 7 janvier 2002
Statut
Membre
Dernière intervention
10 février 2010
1
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
Afficher les 35 commentaires

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.