Controles Personalizados en ASP.NET

En esta oportunidad quiero mostrar un ejemplo sencillo de como realizar un control personalizado, éste simplemente va a extender el control TextBox que trae el .NET Framework, haciendo que sólo acepte valores definidos en una expresión regular.

Nuestra clase tendrá dos atributos: characterExpression y validationExpression, el primero será la expresión regular que controle si una letra es válida o no (Ej. \d si se desea que sólo acepte números), mientras que el segundo sirve para validar el valor final (Ej. \d{3} para un número con tres dígitos).

A continuación sobre-escribiremos los métodos AddAttributesToRender -donde agregamos los eventos de cliente onkeypress/onchange- y OnPreRender, en el cuál se registra la referencia al código de cliente que está como recurso embedido.

csharp:
protected override void AddAttributesToRender(HtmlTextWriter writer)
{
        if (!string.IsNullOrEmpty(characterExpression))
                Utils.AddAttribute(this, "onkeypress",
                                        string.Format("bc_ValidarCaracter(event, '{0}')",
                                                characterExpression.Replace("\", "\\").Replace("'", "\'")));

        if (!string.IsNullOrEmpty(validationExpression))
                Utils.AddAttribute(this, "onchange",
                                        string.Format("bc_LimpiarValor(this, '{0}')",
                                                validationExpression.Replace("\", "\\").Replace("'", "\'")));

        base.AddAttributesToRender(writer);
}

protected override void OnPreRender(EventArgs e)
{
        base.OnPreRender(e);
        if (!string.IsNullOrEmpty(characterExpression) || !string.IsNullOrEmpty(validationExpression))
                Page.ClientScript.RegisterClientScriptResource(GetType(), "Buayacorp.Web.Resources.script.js");
}

Un aspecto importante al desarrollar este tipo de controles, es decidir cómo mantener el estado de las propiedades del control, hasta antes de ASP.NET 2, esto normalmente se realizaba utilizando el ViewState, dichos controles funcionaban bien siempre y cuando esta característica haya sido habilitada, sin embargo ahora existe algo que se llama "Control State", el cuál permite almacenar las propiedades no importando si el ViewState está habilitado o no, cabe aclarar que ésta característica de manera predeterminada  hace uso del mismo campo que utiliza el ViewState.

Utilice el estado del control sólo para pequeñas cantidades de datos críticos que sean esenciales para el control en las distintas devoluciones de datos. No debe utilizar el estado del control como alternativa al estado de vista.

Una vez aclarado estos conceptos, considero que nuestro control debe tener datos válidos no importando si el ViewState está habilitado o no.

csharp:
protected override void OnInit(EventArgs e)
{
        Page.RegisterRequiresControlState(this);
        base.OnInit(e);
}
protected override object SaveControlState()
{
        Pair state = new Pair();
        state.First = base.SaveControlState();

        state.Second = new string[] { characterExpression, validationExpression };

        return state;
}

protected override void LoadControlState(object state)
{
        Pair p = state as Pair;
        if (p != null)
        {
                base.LoadControlState(p.First);

                string[] v = p.Second as string[];

                if (v != null)
                {
                        characterExpression = v[0];
                        validationExpression = v[1];
                }
        }
}

A continuación ponemos el siguiente código en el archivo script.js, que será un recurso embedido del ensamblado de nuestro control.

Código Javascript

Finalmente, necesitamos que nuestro ensamblado permita que el archivo script.js sea reconocido como recurso Web, para esto usamos el atributo WebResource.

csharp:
[assembly: System.Web.UI.WebResource("Buayacorp.Web.Resources.script.js",
                "text/javascript")]

Happy coding!

Archivos Relacionados

Nota: el código javascript está mostrado como imagen debido a que tenemos ciertas restricciones por el mod_security de nuestro hosting.

3 Replies to “Controles Personalizados en ASP.NET”

  1. Hola, he estado investigando el uso de ControlState y he hecho algunos ejemplos de prueba pero se me presenta el problema de que cuando ejecuto paso a paso el código, sí entra al SaveControlState pero nunca entra a LoasControlState por lo cual nunca puedo recuperar el estado guardado en el postback anterior. No sé si esté método es invocado por el mismo .NET Framework al cargar el formulario o si debo invocarlo yo manualmente desde algún lado.
    El código de ejemplo es el siguiente:

    vbnet:

    Imports System.Web
    Imports System.Web.UI
    Imports System.Web.UI.WebControls

    Namespace DJ
        Public Class ControlDJ
            Inherits WebControl
            Implements INamingContainer

            Private _objeto As Object

            Public Property SelectedObject() As Object
                Get
                    Return _objeto
                End Get
                Set(ByVal Value As Object)
                    _objeto = Value
                End Set
            End Property

            Protected Overrides Sub CreateChildControls()
                If Not Page.IsPostBack Then
                    Dim boton1 As New Button
                    boton1.ID = "boton1"
                    boton1.Text = "Enviar"
                    Me.Controls.Add(boton1)
                End If
            End Sub

            Protected Overrides Sub OnInit(ByVal e As System.EventArgs)
                Page.RegisterRequiresControlState(Me)
                MyBase.OnInit(e)
            End Sub

            Protected Overrides Function SaveControlState() As Object
                Dim obj As Object = MyBase.SaveControlState()

                If obj IsNot Nothing Then
                    Return New Pair(obj, _objeto)
                Else
                    Return _objeto
                End If

            End Function

            Protected Overrides Sub LoadControlState(ByVal state As Object)
                If (state IsNot Nothing) Then
                    Dim p As Pair = TryCast(state, Pair)
                    If p IsNot Nothing Then
                        MyBase.LoadControlState(p.First)
                        _objeto = p.Second
                    Else
                        _objeto = state
                    End If
                End If
            End Sub

        End Class
    End Namespace

    Desde ya agradeceré cualquier ayuda que puedan proporcionarme.
    Saludos, Diego

  2. Diego, la implementación del control parece correcta, pero habría que ver como lo estás usando y qué resultados realmente esperas.

    Saludos

Comments are closed.