Bewise

Nous développons... votre avance

Création d’un ScriptControl AJAX : L’AutoCompleteScriptControl

SLF
SWA
14/05/2007 - Sébastien Pertus
Télécharger la version Word
Télécharger les sources

1 Introduction

Dans un précédent article, nous avons découvert les possibilités offertes par, à la fois le Framework ASP.Net Ajax Extensions 1.0 et le Framwork de l’ATLAS toolkit, pour créer de toutes pièces un Extender ; permettant ainsi d’étendre le comportement d’un contrôle existant.

Je vous invite à parcourir cet article avant d’entamer celui-ci pour bien fixer les bases du développement de composants extenders.

Nous étions arrivés à la fin de ce précédent article en concluant qu’il n’était pas possible de rajouter de comportement purement AJAX à notre contrôle en invoquant par exemple une méthode depuis notre JavaScript.

Heureusement la Toolkit nous permet aujourd’hui de contourner ce problème et nous fournit une classe de base permettant d’implémenter de telles fonctionnalités : Le ScriptControl.

2 Comparaison des deux modèles

Nous allons comparer les deux classes principales de l’ATLAS Toolkit nous permettant d’étendre ou de créer des contrôles.

D’un coté nous avons les Extenders, issus de la classe ExtenderControlBase (qui hérite elle-même de la classe ExtenderControl) et de l’autre les ScriptsControls qui héritent eux de la class ScriptControlBase (qui hérite elle-même de la classe ScriptControl)

Finalement ces deux classes encapsulent chacun à leur manière les deux interfaces fournies par le Framework Ajax.Net Extensions 1.0, à savoir IExtenderControl pour le premier et IScriptControl pour le second.

Le raisonnement de la communauté de développement de la toolkit reste donc très cohérent.

2.1 ExtenderBase

C’est de cette classe que nous avons héritée dans notre premier article pour créer notre extender.

Le problème c’est qu’elle n’hérite pas de WebControl (mais de Control) et n’implémente pas l’interface ICallbackEventHandler (Inutile de toute façon puisque seul les WebControls ont une chance de voir leur méthodes, implémentées par cette interfaces, appelées.)

Voilà donc la limitation de cette classe quand on essaie d’implémenter du CallBack Ajax.

2.2 ScriptControlBase

Cet article va se focaliser sur cette classe abstraite qui va nous permettre de développer notre contrôle.

Si l’on observe bien cette classe, on peut voir déjà dans sa définition, qu’elle hérite de ScriptControl biensur, mais aussi de WebControl, ce qui est une bonne nouvelle et nous conforte dans l’idée que nous pourrons suremment implémenter tout un tas d’interfaces pour mettre en place du CallBack et du PostBack :

public abstract class ScriptControl : WebControl, IScriptControl { protected ScriptControl(); protected abstract IEnumerable<ScriptDescriptor> GetScriptDescriptors(); protected abstract IEnumerable<ScriptReference> GetScriptReferences(); protected override void OnPreRender(EventArgs e); protected override void Render(HtmlTextWriter writer); }

D’ailleurs c’est exactement ce que fait la classe ScriptControlBase !

public class ScriptControlBase : ScriptControl, INamingContainer, IControlResolver, IPostBackDataHandler, ICallbackEventHandler, IClientStateManager { … }

Nous avons donc une classe qui masque quelque peu la tuyauterie en encapsulant tous ces mécanismes de base et nous permettre de nous focaliser sur notre contrôle et son fonctionnement métier.

2.3 Quelle différence ?

Quelle est la différence entre ScriptControl et ExtenderBase ?

Et bien pour faire simple, l’Extender va nous permettre de créer un contrôle qui étend les fonctionnalités d’un contrôle existant, tandis que le ScriptControl lui est une base pour créer un nouveau contrôle de toute pièce (et non pas étendre un contrôle).

Vous avez déjà un exemple dans la toolkit, en la personne du TabControl, qui n’étend pas de contrôle existant. C’est un contrôle à part entière !

public class TabContainer : ScriptControlBase { …. }

3 Notre contrôle : AutoCompleteControl

Il existe déjà dans la toolkit un Extender qui permet d’étendre le comportement d’un TextBox en permettant d’afficher un Layer en dessous avec les résultats d’une requête renvoyées par un WebService : l’AutoCompleteExtender

Attention : Il s’agit bien là d’un Extender. L’AutoCompleteExtender a contourné les problèmes des requêtes Ajax en allant chercher les résultats via l’appel asynchrone en JavaScript d’un WebService (Le Framework Asp.Net Ajax Extensions permettant cela de manière assez élégante !)

Nous ; nous voulons la même chose, si ce n’est que nous voulons appeler non pas un WebService, mais plutôt une méthode interne, et évidemment tout cela en Ajax, pour une utilisation agréable du contrôle.

image

4 Création du projet

Comme pour l’extender nous allons créer un projet sur la base du Template fournit par l’AtlasTookit, pour arriver à ce résultat :

image

La Classe AutoCompleteScriptControl doit être modifiée et ne doit plus hériter d’ExtenderBase mais plutôt de ScriptControl :

[assembly: System.Web.UI.WebResource("AutoCompleteControl.AutoCompleteScriptControl.js", "text/javascript")] namespace AutoCompleteControl { [ClientScriptResource("AutoCompleteControl.AutoCompleteScriptControl", "AutoCompleteControl.AutoCompleteScriptControl.js")] [RequiredScript(typeof(CommonToolkitScripts))] [RequiredScript(typeof(PopupExtender))] [RequiredScript(typeof(TimerScript))] [Designer(typeof(AutoCompleteScriptControlDesigner))] public class AutoCompleteScriptControl : ScriptControlBase, IDataSource { public AutoCompleteScriptControl(): base(false) { } }

Deux choses à remarquer :

· Le fichier AutoCompleteView.cs et l’interface IDataSourceControl : Nous allons y revenir plus tard mais sachez que c’est l’implémentation d’un Pattern DataSourceControl

· Le rajout des Scripts requis pour notre contrôle :

o PopupExtender : L’ensemble des fonctions Javascript amenées par la toolkit pour générer et gérer des popup. Impossible d’imaginer la simplicité d’utilisation de création d’un popup avant de l’avoir essayé !

o TimerScript : L’ensemble des fonctions Javascript pour gérer le temps et les intervalles de temps. Dans notre cas, cela nous permettra de gérer les intervalles de temps entre chaque requête et la vérification du contenu de la TextBox (si celui-ci a évolué ou non)

5 Un ObjectDataSource embarqué

Pour nous rapprocher au plus prés des habitudes des développeurs asp.net en général, il serait de bon aloi de leur fournir un moyen dont ils ont l’habitude pour accéder à la classe capable de renvoyer les informations à afficher dans le Popup.

Aujourd’hui lorsque l’on veut lier un contrôle à une source de donnée, la plupart du temps, nous pouvons passer par un Contrôle ObjectDataSource auquel nous fournissons une méthode Select via la propriété SelectMethod ainsi qu’une liste de paramètres à passer à cette méthode.

Nous allons donc développer un ObjectDataSource embarqué dans notre Contrôle !

Pour ce faire nous allons implémenter un Pattern DataSourceControl.

Si nous prenons exemple sur l’ObjectDataSource, on peut le décomposer en deux objets distincts :

L’ObjectDataSource : C’est la classe que l’on utilise tous, qui permet de définir les paramètres, les noms de méthodes etc… C’est purement un contrôle visuel.

Cette classe implémente l’interface IDataSource.

Note : Aurait-on pu plutôt pu hériter de la classe DataSourceControl ? Non, puisque nous héritons déjà de ScriptControlBase !

L’ObjectDataSourceView : C’est une classe non visible, mais c’est elle qui fera tout le boulot de requêtage, réflexion et analyse de paramètres renvoyés par l’ObjectDataSource. Bien sur, elle renvoie le résultat de la requête sous format IEnumerable.

Cette classe hérite de DataSourceView.

Dans notre cas, la classe implémentant IDataSource sera notre contrôle lui-même, permettant ainsi de récupérer les valeurs de la méthode SelectMethod et l’ensemble des paramètres.

Nous créons ensuite une classe AutoCompleteView héritant de DataSourceView.

L’objet de cet article n’étant pas de décortiquer cette implémentation, je vous laisse découvrir le code par vous-même, qui reste relativement simple à comprendre.

A quoi cela servira-t’il dans notre contrôle au final ?

Il suffit de voir son implémentation dans notre designer :

<cc1:AutoCompleteScriptControl Width="200px" ID="txtProductSearchPostBack" runat="server" DataTextField="Name" DataValueField="Id" SelectMethod="GetList" TypeName="WebExtenderAjax.ProductManager" CompletionInterval="200"> <SelectParameters> <asp:ControlParameter ControlID="txtProductSearchPostBack" Name="name" PropertyName="Text" /> </SelectParameters> </cc1:AutoCompleteScriptControl>

On constate que notre contrôle devra appeller la méthode GetList de la classe WebExtenderAjax.ProductManager, et qui attend un paramètre nommé name.

Ce qui correspond bien à l’appel de cette méthode :

namespace WebExtenderAjax { public class ProductManager { public Product GetProduct(int Id) { Product e = null; SqlConnection conn = new SqlConnection(WebExtenderAjax.Properties.Settings.Default.AdvConnectionString); SqlCommand comm = new SqlCommand("Select * from Production.Product where ProductID = @ProductID", conn); SqlParameter p = new SqlParameter("@ProductID", SqlDbType.Int); p.Value = Id; comm.Parameters.Add(p); conn.Open(); try { SqlDataReader dr = comm.ExecuteReader(); while (dr.Read()) { e = new Product(); e.Id = (int)dr["ProductID"]; e.ProductNumber = (String)dr["ProductNumber"]; e.Name = (String)dr["Name"]; e.SellStartDate = (DateTime)dr["SellStartDate"]; } dr.Close(); } catch (Exception ex) { Debug.WriteLine(ex.Message); } finally { conn.Close(); } return e; }

6 Propriétés et méthodes de notre Contrôle

Pour les propriétés, on reste fidèle à ce que nous avons vu dans le précédent article, à savoir :

· Marquer les propriétés dont nous avons besoin coté Javascript avec l’attribut ExtenderControlProperty

· Respecter la casse de cette propriété et utiliser l’attribut ClientPropertyName si nécessaire

· Enfin, ne pas oublier de gérer la persistance en utilisant le ViewState

/// <summary> /// Identifiant de la zone de texte /// </summary> [ExtenderControlProperty] [DefaultValue("")] [ClientPropertyName("textBoxBehaviorID")] [Browsable(false)] public string TextBoxBehaviorId { get { return (string)(ViewState["TextBoxBehaviorId"] ?? string.Empty); } set { ViewState["TextBoxBehaviorId"] = value; } }

Pour les méthodes, ce que nous ne pouvions faire avec un Extender, nous allons enfin pouvoir le gérer ici : Marquer une méthode comme méthode Ajax !

Pour rester dans la lignée des propriétés, il devient naturel d’appliquer l’attribut ExtenderControlMethod sur notre méthode et ainsi lui signifier que cette méthode sera appelée depuis notre code JavaScript :

/// <summary> /// Exécution de la méthode de sélection /// </summary> [ExtenderControlMethod] public Object[] SelectForCallbackReturn(string param) { this.Text = param; IEnumerable returnList = this.GetView().ExecuteSelect(); ArrayList al = ArrayList.Adapter(returnList as IList); return al.ToArray(); }

7 Implémentation JavaScript

Il ne reste plus qu’à implémenter le code JavaScript, la partie préférée de nombre d’entre nous !

Mais comme vous le savez maintenant, le framework Asp.Net Ajax Extensions nous aide grandemenent dans cette tache en nous permettant notamment de nous abstraire des soucis du navigateur cible, par exemple.

Je passe très vite sur la récupération des propriétés, le principe restant identique à notre précédent article.

Pour la méthode permettant d’appeler de façon asynchrone notre méthode managée, il suffit de respecter une règle simple, mais efficace :

1) Créer un délégué sur une fonction qui sera exécuté au retour de l’appel de notre méthode.

2) Appeler la méthode via la fonction JavaScript this._invoke en lui passant en paramètre le délégué.

En code :

1) Création du délégué et de sa méthode

// Evènement sur le retour d'informations aprés appel Ajax this._cbcomplete$delegate = Function.createDelegate(this, this._cbcomplete);

_cbcomplete: function(result, context) { /// <summary> /// <value type="String>Résulat retour</value> /// <summary> this._update(context, result, /* cacheResults */ true); },

2) Appel de la méthode via this._invoke

this._invoke('SelectForCallbackReturn', [text], this._cbcomplete$delegate);

8 Le reste

Pour le fonctionnement interne de ce contrôle, je me suis plus que fortement inspiré du contrôle AutoCompleteExtender de l’AtlasToolKit.

Comme celui-ci, notre contrôle gère un cache, qui évite de relancer des requêtes si le résultat est en cache.

Autre point notable, la gestion des touches du clavier, là aussi simplifiée et unifiée grâce au Framework ASP.net Ajax Extensions 1.0

Le placement de la Div transparente se fait quant à lui à l’aide des fonctions fournies par l’api PopuExtender de l’AtlasToolkit.

Pour le design de notre contrôle dans Visual Studio, j’ai quelque peu modifié le comportement de base pour y intégrer le logo de ma société (non ce n’est pas de la pub déguisée ;))

9 Conclusion

Nous avons vu dans cet article comment utiliser le Framework ASP.Net Ajax Extensions 1.0 ainsi que le Framework de l’ATLAS Toolkit, pour créer un ScriptControl assez évolué.

Pour celles et ceux qui se demandent, en terme de performance, lequel entre celui-ci et l’AutoCompleteExtender, est le plus performant… la question fait grand débat chez nous ! Si quelqu’un souhaite faire un benchmark et discuter des résultats, je suis ouvert.

Enjoy !

> Tous les articles

Commentaires

aucun commentaire
Page 1/1
   
Connexion
  • Accueil
  • Plan du site
  • Contact
Bewise TV, Blog technique, Webcasts...

Votre carrière et nous

  • Nos offres
  • Votre candidature
Ignorer les liens de navigation > Accueil > Nos Métiers > Solutions Web Avancées > Détail Article
Ignorer les liens de navigation
Nous
Nos Métiers
Vous Former
Nos Evènements
Nos Références
Nos Activités
Nos Certifications
Nos Chiffres
Le Groupe
Nos Partenaires
On Parle de Nous
Nous contacter
Votre Carrière et Nous
Défiler vers le haut
Défiler vers le bas
Administration, Système et Communication
Architecture, Méthodes, Industrialisation
Décisionnel et Gestion des Données
Nouvelles Interfaces Utilisateurs
Portail et Travail Collaboratif
Solutions Langages et Framework
Solutions Web Avancées
Défiler vers le haut
Défiler vers le bas
Nos cours
Le Planning
Offres promotionnelles
Défiler vers le haut
Défiler vers le bas
Bewise Day Conference 2011
Nos Expresso
Défiler vers le haut
Défiler vers le bas
  • Infos légales
  • Lettre du Regional Director
  • Revue de presse