Bienvenue à Blogs CodeS-SourceS Identification | Inscription | Aide

Atteint de JavaScriptite Aiguë [Cyril Durand]

Expert ASP.net Ajax et WCF, Cyril Durand parle dans son blog de point techniques sur ASP.net, ASP.net Ajax, JavaScript, WCF et .net en général. Cyril est également consultant indépendant, n'hésitez pas à le contacter pour de l'assistance sur vos projets

Actualités

  • Blog de Cyril DURAND, passionné de JavaScript, Ajax, ASP.net et tout ce qui touche au developpement Web Client-Side.

    N'hésitez pas à me contacter pour vos projets .net : architecture, accompagnement, formation, ...

    View Cyril Durand's profile on LinkedIn
    hit counters


    Expertise Commerce server et BizTalk

L'interface ITemplate lors de la compilation d'une page en ASP.net

L'interface ITemplate est souvent mal comprise des développeurs, cette interface permet de faire des contrôles ayant la notion de template, c'est à dire que le développeur peut modifier certaines parties du code HTML généré par le contrôle, c'est le cas du Repeater, GridView ...  Voyons comment l'utiliser dans un simple contrôle d'exemple.

[PersistChildren(false)] [ParseChildren(true)] public class TestTemplate : WebControl { private ITemplate _myTemplate; [PersistenceMode(PersistenceMode.InnerProperty)] public ITemplate MyTemplate { get { return _myTemplate; } set { _myTemplate = value; } } protected override void CreateChildControls() { if (_myTemplate != null) { _myTemplate.InstantiateIn(this); } base.CreateChildControls(); } }

on peut utiliser ce contrôle ainsi :

<test:testtemplate runat="server" id="tt"> <MyTemplate> Coucou du template </MyTemplate> </test:testtemplate>

L'attribut PersistChildren permet de dire que le contrôle ne prend pas de contrôles enfant, comme c'est le cas par exemple pour un panel, l'attribut ParseChildren indique que le contenu du contrôle correspond aux valeurs de propriétés et enfin l'attribut PersistenceMode spécifie que cette propriété sera renseigné à l'interieur du contrôle.

Bien sur cet exemple est complétement inutile, les templates servent surtour lorsque vous avez des contrôles qui sont liés à une liste d'éléments, comme le repeater ou alors pour personaliser une partie du rendu d'un controle comme pour le Wizard

On peut également définir la propriété dynamiquement en utilisant la méthode Page.LoadTemplate("montemplate.ascx") ou alors en créant une classe qui implémentera ITemplate avec sa méthode InstanciateIn qui rajoutera les contrôles enfants dans le contrôle passé en paramètre de cette méthode. J'ai d'ailleurs parlé de la méthode LoadTemplate ici : Page.LoadTemplate - charger un UserControl dans une propriété ITemplate  

Mais regardons plutôt ce qui se passe lors de la compilation de cette page avec Reflector :

private TestTemplate __BuildControltt() { TestTemplate template = new TestTemplate(); base.tt = template; template.ApplyStyleSheetSkin(this); template.MyTemplate = new CompiledTemplateBuilder(new BuildTemplateMethod(this.__BuildControl__control4)); template.ID = "tt"; return template; } private void __BuildControl__control4(Control __ctrl) { IParserAccessor accessor = __ctrl; accessor.AddParsedSubObject(new LiteralControl("\r\n Coucou du template\r\n ")); }

Et voici le code de CompiledTemplateBuilder

public sealed class CompiledTemplateBuilder : ITemplate { // Fields private BuildTemplateMethod _buildTemplateMethod; // Methods public CompiledTemplateBuilder(BuildTemplateMethod buildTemplateMethod) { this._buildTemplateMethod = buildTemplateMethod; } public void InstantiateIn(Control container) { this._buildTemplateMethod(container); } }

Lors de la compilation, la propriété MyTemplate prend une instance de CompiledTemplateBuilder qui ne fait qu'appeler la méthode passé en paramètre de son constructeur lorsqu'on appelle la méthode InstantiateIn. Autrement dit, lorsque l'on appelle la méthode InstantiateIn de la propriété de type ITemplate cela va rajouter le code HTML à la collection de contrôles de l'élément qu'on passe en paramètre. Dans notre exemple lors de l'appel de la méthode CreateChildControls, on appelle la méthode InstantiateIn qui va rajouter un new LiteralControl("\r\n           Coucou du template\r\n     ")  à la collection de contrôle de notre contrôle.

Modifions un peu notre code afin d'utiliser l'expression "<%# Container", pour cela nous devons être dans un contexte de Binding, cela se produit lorsque l'on appel la méthode DataBind.

protected override void CreateChildControls() { if (_myTemplate != null) { _myTemplate.InstantiateIn(this); this.DataBind(); } base.CreateChildControls(); }

<test:testtemplate runat="server" id="tt"> <MyTemplate> <%# "le type de container est " + Container.ToString() %> </MyTemplate> </test:testtemplate>

Comment est compilé cette page aspx, pour le savoir regardons le résultat de la publication avec Reflector.

private TestTemplate __BuildControltt() { TestTemplate template = new TestTemplate(); base.tt = template; template.ApplyStyleSheetSkin(this); template.MyTemplate = new CompiledTemplateBuilder( new BuildTemplateMethod(this.__BuildControl__control4)); template.ID = "tt"; return template; } private void __BuildControl__control4(Control __ctrl) { DataBoundLiteralControl control = this.__BuildControl__control5(); IParserAccessor accessor = __ctrl; accessor.AddParsedSubObject(control); } private DataBoundLiteralControl __BuildControl__control5() { // attention syntaxe C#3 DataBoundLiteralControl control = new DataBoundLiteralControl(2, 1) { TemplateControl = this }; control.SetStaticString(0, "\r\n "); control.SetStaticString(1, "\r\n "); control.DataBinding += new EventHandler(this.__DataBind__control5); return control; } public void __DataBind__control5(object sender, EventArgs e) { DataBoundLiteralControl control2 = (DataBoundLiteralControl) sender; Control bindingContainer = control2.BindingContainer; control2.SetDataBoundString(0, Convert.ToString("le type de container est " + bindingContainer.ToString(), CultureInfo.CurrentCulture)); }

La différence par rapport à tout à l'heure et que la compilation créer un nouveau contrôle de type DataBoundLiteralControl qui contiendra tous le code html du template, ce code html est dynamique puisqu'il est modifié lors de l'événement DataBinding. Si on regarde la méthode __DataBind__control5, on voit que notre objet Container correspond à la propriété BindingContainer du DataBoundLiteralControl. Voici comment cette propriété est définit.

public Control BindingContainer { get { Control namingContainer = this.NamingContainer; while (namingContainer is INonBindingContainer) { namingContainer = namingContainer.BindingContainer; } return namingContainer; } }

Cette propriété de type Control, ne fait que rechercher le NamingContainer du DataBoundLiteralControl, qui est lui même rajouté à notre contrôle. Dans notre cas le NamingContainer correspond donc à la page. Mais généralement le parent de la propriété ITemplate implémente INamingContainer. Pour rappel cette interface n'est qu'un marqueur qui permet d'avoir des ID de contrôles uniques, elle est donc indispensable si l'on utilise plusieurs fois le template dans notre contrôle, ce qui est le cas pour le Repeater.

On sait maintenant vers quel objet pointe l'objet Container. On peut donc l'utiliser un peu plus astucieusement, par exemple en rajouter une propriété à notre Container et ainsi y accéder directement dans la page aspx :

<test:TestTemplate runat="server" ID="tt" MyProperty="toto"> <MyTemplate> <%# ((TestTemplate)Container).MyProperty %> </MyTemplate> </test:TestTemplate>

Nous avons vu tout à l'heure que l'objet Container était du type Control, il nous faut donc caster Container en TestTemplate pour avoir accès à notre propriété. L'attribut TemplateContainer permet justement de modifier le type de cet objet !

[PersistenceMode(PersistenceMode.InnerProperty)] [TemplateContainer(typeof(TestTemplate))] public ITemplate MyTemplate { get { return _myTemplate; } set { _myTemplate = value; } }

nous permet alors d'écrire

<test:TestTemplate runat="server" ID="tt" MyProperty="toto"> <MyTemplate> <%# Container.MyProperty %> </MyTemplate> </test:TestTemplate>

Nous verrons dans un prochain post un exemple d'utilisation plus concrète des Itemplate et de l'attribut TemplateContainer au sein d'un CompositeDataBoundControl.


Pour ceux qui sont interressé par savoir comment connaitre le résultat de la compilation d'une page ASP.net, j'en ai parlé ici : Obtenir le resultat de la compilation d'une page ASP.net

Posted: dimanche 6 mai 2007 04:08 par cyril
Ce post vous a plu ? Ajoutez le dans vos favoris pour ne pas perdre de temps à le retrouver le jour où vous en aurez besoin :

Commentaires

Pas de commentaires

Les commentaires anonymes sont désactivés

Les 10 derniers blogs postés

- Office 365: Script PowerShell pour auditer l’usage des Office Groups de votre tenant par Blog Technique de Romelard Fabrice le 04-26-2019, 11:02

- Office 365: Script PowerShell pour auditer l’usage de Microsoft Teams de votre tenant par Blog Technique de Romelard Fabrice le 04-26-2019, 10:39

- Office 365: Script PowerShell pour auditer l’usage de OneDrive for Business de votre tenant par Blog Technique de Romelard Fabrice le 04-25-2019, 15:13

- Office 365: Script PowerShell pour auditer l’usage de SharePoint Online de votre tenant par Blog Technique de Romelard Fabrice le 02-27-2019, 13:39

- Office 365: Script PowerShell pour auditer l’usage d’Exchange Online de votre tenant par Blog Technique de Romelard Fabrice le 02-25-2019, 15:07

- Office 365: Script PowerShell pour auditer le contenu de son Office 365 Stream Portal par Blog Technique de Romelard Fabrice le 02-21-2019, 17:56

- Office 365: Script PowerShell pour auditer le contenu de son Office 365 Video Portal par Blog Technique de Romelard Fabrice le 02-18-2019, 18:56

- Office 365: Script PowerShell pour extraire les Audit Log basés sur des filtres fournis par Blog Technique de Romelard Fabrice le 01-28-2019, 16:13

- SharePoint Online: Script PowerShell pour désactiver l’Option IRM des sites SPO non autorisés par Blog Technique de Romelard Fabrice le 12-14-2018, 13:01

- SharePoint Online: Script PowerShell pour supprimer une colonne dans tous les sites d’une collection par Blog Technique de Romelard Fabrice le 11-27-2018, 18:01