Création d'un Custom WebControl avec du JavaScript embedded

Mon précédent article expliquait comment réaliser simplement un contrôle en prenant un peu la main sur ce qui se faisait en ASP.NET et en simplifiant les propriétés pour coller plus au besoin réel. Nous continuons dans cette direction mais en offrant maintenant à notre contrôle de nouvelles options. Nous ne voulons pas toujours exécuter toutes les validations côté serveur... En effet, certaines sont simples et peuvent s'effectuer sur le poste client. Par exemple ici, un pourcentage est toujours compris entre 0 et 100. Nous devons donc changer notre classe pour lui ajouter un "support" du JavaScript. Ce support permettra d'avoir une classe JavaScript de définie et instanciée pour chaque contrôle de ce type rendu à l'écran. Nous  mettrons le border en rouge si la valeur encodée dans la textbox est incorrecte.

La première étape est d'ajouter l'interface IScriptControl (qui se trouve dans la dll System.Web.Extensions) sur notre classe pourcentage.

[DefaultProperty("Value")]
[ToolboxData("<{0}:PercentageControl runat=server></{0}:PercentageControl>")]
[ToolboxBitmap(typeof(PercentageControl), "Percentage.bmp")]
public class PercentageControl : WebControlIPostBackDataHandlerIScriptControl

Nous devons ensuite enregistrer cette classe dans le ScriptManager comme nous avons dû le faire pour enregistrer celle-ci dans le support du PostBack.

protected override void OnPreRender(System.EventArgs e)
{
    if (!this.DesignMode)
    {
        ScriptManager sm = ScriptManager.GetCurrent(Page);
        if (sm == null)
        {
            throw new HttpException("A ScriptManager control must exist on the page.");
        }
        sm.RegisterScriptControl(this);
    }
    base.OnPreRender(e);
    this.Page.RegisterRequiresPostBack(this);
}
protected override void Render(HtmlTextWriter writer)
{
    if (!this.DesignMode)
    {
        ScriptManager sm = ScriptManager.GetCurrent(Page);
        sm.RegisterScriptDescriptors(this);
    }
    base.Render(writer);
}

Il est temps de passer à l'implémentation de l'interface IScriptControl. Il faut donner le nom de la classe JavaScript liée au contrôle C# ainsi que les propriétés que l'on envoie à la classe JavaScript. Cela se passe dans la méthode GetScriptDescriptors. De l'autre côté, il faut spécifier le chemin pour accéder au fichier JavaScript où se trouve ma (future) classe JavaScript. Cela se passe dans la méthode GetScriptReferences.

public IEnumerable<ScriptDescriptor> GetScriptDescriptors()
{
    ScriptControlDescriptor descriptor = new ScriptControlDescriptor("MyCustomControls.PercentageControl"this.ClientID);
    descriptor.AddProperty("errorCssClass"this.ErrorCssClass);
    return new ScriptDescriptor[] { descriptor };
}
public IEnumerable<ScriptReference> GetScriptReferences()
{
    ScriptReference reference = new ScriptReference();
    if (this.Page != null)
    {
        reference.Path = this.Page.ClientScript.GetWebResourceUrl(
                                        this.GetType(),
                                        "MyCustomControls.PercentageControl.js");
    }
    return new[] { reference };
}

Nous pouvons démarrer notre classe JavaScript. Nous décidons de la placer dans une ressource "embedded" de notre dll. Nous ajoutons notre fichier PercentageControl.js et nous l'enregistrons comme ressource dans notre assembly via cet déclaration ci-dessous.

[assemblyWebResource("MyCustomControls.PercentageControl.js""text/javascript")]

La prochaine étape est l'implémentation de celle-ci.

1) Nous enregistrons notre namespace

Type.registerNamespace('MyCustomControls');


2) Nous allons initialiser les valeurs par défauts etc

MyCustomControls.PercentageControl = function (element) {
    MyCustomControls.PercentageControl.initializeBase(this, [element]);
    this._errorCssClass = null;
};


3) Nous implémentons notre classe protoype avec 2 méthodes .... initialize et dispose

MyCustomControls.PercentageControl.prototype = {
    initialize: function () {
        MyCustomControls.PercentageControl.callBaseMethod(this'initialize');
    },
    dispose: function () {
        $clearHandlers(this.get_element());
        MyCustomControls.PercentageControl.callBaseMethod(this'dispose');
    }
};

4) Nous implémentons les propriétés pour le css d'erreur à appliquer en JavaScript

MyCustomControls.PercentageControl.prototype = {
    initialize: function () {
        MyCustomControls.PercentageControl.callBaseMethod(this'initialize');
    },
    dispose: function () {
        $clearHandlers(this.get_element());
        MyCustomControls.PercentageControl.callBaseMethod(this'dispose');
    },
    set_errorCssClass: function (value) {
        if (this._errorCssClass !== value) {
            this._errorCssClass = value;
            this.raisePropertyChanged('errorCssClass');
        }
    },
    get_errorCssClass: function () {
        return this._errorCssClass;
    }
};

5) Nous donnons explicitement les descripteurs (utile pour la sérialisation JSON)

MyCustomControls.PercentageControl.descriptor = {
    properties: [{ name: 'errorCssClass', type: String}]
};

6) Nous enregistrons la classe et nous informons le framework que c'est chargé.

MyCustomControls.PercentageControl.registerClass('MyCustomControls.PercentageControl', Sys.UI.Control);
if (typeof (Sys) !== 'undefined') Sys.Application.notifyScriptLoaded();

7) Nous souhaitons implémenter notre code "business"

L'idée est de mettre un cadre rouge autour des texbox lorsqu'il y a une erreur. Pour ce faire, nous allons nous abonner à l'event change et ajouter notre css d'erreur en cas de donnée incorrecte. Nous obtenons au final le résultat ci-dessous.

Type.registerNamespace('MyCustomControls');
MyCustomControls.PercentageControl = function (element) {
    MyCustomControls.PercentageControl.initializeBase(this, [element]);
    this._errorCssClass = null;
};
MyCustomControls.PercentageControl.prototype = {
    initialize: function () {
        MyCustomControls.PercentageControl.callBaseMethod(this'initialize');
        this._onchangeHandler = Function.createDelegate(thisthis._onchange);
        $addHandlers(this.get_element(), { 'change'this._onchangeHandler }, this);
    },
    dispose: function () {
        $clearHandlers(this.get_element());
        MyCustomControls.PercentageControl.callBaseMethod(this'dispose');
    },
    _onchange: function (e) {
        var value = parseFloat(e.target.value);
        var isIncorrect = false;
        if (isNaN(value) || !isFinite(value)) {
            isIncorrect = true;
        }
        if (isIncorrect || value > 100 || value < 0) {
            if (this._errorCssClass !== null && this._errorCssClass !== '') {
                this.addCssClass(this._errorCssClass);
            }
        }
        else {
            this.removeCssClass(this._errorCssClass); 
        }
    },
    set_errorCssClass: function (value) {
        if (this._errorCssClass !== value) {
            this._errorCssClass = value;
            this.raisePropertyChanged('errorCssClass');
        }
    },
    get_errorCssClass: function () {
        return this._errorCssClass;
    }
};
MyCustomControls.PercentageControl.descriptor = {
    properties: [{ name: 'errorCssClass', type: String}]
};
MyCustomControls.PercentageControl.registerClass('MyCustomControls.PercentageControl', Sys.UI.Control);
if (typeof (Sys) !== 'undefined') Sys.Application.notifyScriptLoaded();

Il ne reste plus qu'à ajouter ma class css dans ceux-ci

<style type="text/css">
    .errorCss
    {
        border-colorRed;
    }
</style>

et de l'ajouter dans notre code asp.net
 
<div>
    <asp:Button ID="Button1" Text="Click" runat="server" />
    <Custom:PercentageControl ID="PercentageControl1" runat="server" 
        ErrorCssClass="errorCss" Value="100" />
</div>
 
Nous pouvons maintenant l'exécuter et nous voyons que l'on retrouve un cadre rouge si on encode 200, -10 ou encore le "é" dans notre textbox. Vous pouvez retrouver la solution en fichier attaché ci-dessous.

Ajouter un commentaire

Le code HTML est affiché comme du texte et les adresses web sont automatiquement transformées.

Fil des commentaires de ce billet

Page top