3 mar 2012

Controlando el control

Vamos a hacer un control, uno sencillo. Se trata de un simple label para ASP.Net.

Primero añadimos un nuevo proyecto de biblioteca de clases. En mi caso decidí llamarlo foy.Web.Controles de manera que me quede de esa manera también, el namespace correspondiente. Seguidamente añadimos una clase que llamamos FoyLabel. Una vez añadida esta clase añadimos las referencias a System.Web y System.Drawing.

No vamos a partir de cero, si no, que vamos a implementar nuestro label a partir del Label de .Net

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.ComponentModel;

namespace foy.Web.Controles
{
    public class FoyLabel: System.Web.UI.WebControls.Label
    {
        public FoyLabel()
            : base()
        {
        }
    }
}

Nuestro label personalizado, nos servirá tanto para mostrar texto normal o indefinido como para mostrar montos formateados.  Para Lograr este objetivo voy a usar un Enum que represente el tipo de formato que se desea asginarle al label. Luego creo una variable y una propiedad para asignar el tipo de formato al control. Asimismo deseo controlar la cantidad de decimales en caso de que el tipo de formato sea un monto
namespace foy.Web.Controles
{
    public enum DisplayFormat
    {
        ///    <summary>
        ///    Tipo de dato indefinido.</summary>
        NoFormat = 0,

        ///    <summary>
        ///    Tipo de dato caracter.</summary>
        MountFormat = 1,

        /// <summary>
        /// Formato financiero numeros negativos estan en rojo y entre parentesis
        /// </summary>
        FinancialFormat = 2
    }
    public class FoyLabel: System.Web.UI.WebControls.Label
    {
        #region Variables
        
        private DisplayFormat _displayformat;
        private int _numeroDecimales = 2;
        
        #endregion
        
        //constructor
        public FoyLabel()
            : base()
        {
        }

        #region Propiedades

        [Category("Layout"),
       DefaultValue(DisplayFormat.NoFormat),
       Description("Formatea el valor como monto si es necesario")]
        public DisplayFormat DisplayFormat
        {
            get
            {
                return _displayformat;
            }
            set
            {
                _displayformat = value;
            }
        }

        [Bindable(true),
      Category("Data"),
      Description("Número de decimales a mostrar cuando un numero se formatea"),
      DefaultValue(2)]
        public int NumeroDecimales
        {
            get
            {
                return _numeroDecimales;
            }
            set
            {
                _numeroDecimales = value;
            }
        }

        #endregion
    }
}

Una vez realizado Esto podemos sobre escribir el metodo Render para formatear el texto según el formato que se le haya asignado al control.
protected override void Render(HtmlTextWriter writer)
{
    try
    {
        if (Text.Length > 0)
        {
            switch (this.DisplayFormat)
            {
                case (DisplayFormat.FinancialFormat):

                    Text = Text.Replace('(', '-').Replace(")", string.Empty);
                    string cerosdecimales = ConvertirACerosDecimales(_numeroDecimales);
                    decimal montotexto = Convert.ToDecimal(Text);
                    string formato = "{0:#,##" + cerosdecimales + ";(#,##" + cerosdecimales + ");0.00}";
                    this.Text = string.Format(formato, montotexto);
                    if (montotexto < 0)
                    {
                        this.ForeColor = System.Drawing.Color.Red;
                    }
                    break;
                case (DisplayFormat.MountFormat):
                    string formatoMonto = "{0:N" + _numeroDecimales.ToString() + "}";
                    Text = string.Format(formatoMonto, Convert.ToDecimal(Text));
                    break;
            }
        }       
    }
    catch (Exception ex)
    {
        Text = "Se ha producido un error aplicando el formato: " + ex.Message;
    }
    finally
    {
        base.Render(writer);
    }

}

protected string ConvertirACerosDecimales(int numeroDecimales)
{
    string decimales = numeroDecimales == 0 ? string.Empty : ".";
    for (int i = 0; i < numeroDecimales; i++)
    {
        decimales = decimales + "0";
    }
    return decimales;
}

La función ConvertirACerosDecimales es utilitario para convertir la cantidad de decimales en string con los ceros que necesita el formato.

Ya con esto podemos probar el control. Creamos un sitio de prueba, añadimos a una página un Textbox, un Botón  y nuestro Label personalizado. La idea es que digitamos en el textbox y al hacer clic en el botón muestre en nuestro label el texto formateado.
<%@ Page Language="C#" Culture="en-US" UICulture="en-US" AutoEventWireup="true" CodeFile="TestControls.aspx.cs"
    Inherits="TestControls" %>

<%@ Register Assembly="foy.Web.Controles" Namespace="foy.Web.Controles" TagPrefix="cc1" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title>Página de Prueba de Controles</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:ScriptManager ID="ScriptManager1" runat="server" />
    </div>
    <asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
    <asp:Button ID="Button1" runat="server" OnClick="Button1_Click" Text="Button" />
    <br />
    <asp:UpdatePanel ID="UpdatePanel1" runat="server">
        <ContentTemplate>
            <cc1:FoyLabel ID="LabelTest1" runat="server" DisplayFormat="FinancialFormat"></cc1:FoyLabel>
        </ContentTemplate>
        <Triggers>
            <asp:AsyncPostBackTrigger ControlID="Button1" />
        </Triggers>
    </asp:UpdatePanel>
    </form>
</body>
</html>

Es importante registrar nuestro assembly con los controles por medio de la clausula @Register. En el code behind solo tenemos el evento del botón
protected void Button1_Click(object sender, EventArgs e)
{
    LabelTest1.Text = TextBox1.Text;
}

Probamos nuestra página .
Es importante señalar que por medio de la técnica de añadir un tipo Enum público como propiedad de un server control como en este caso se hizo con la propiedad DisplayFormat, los valores del enum quedan como valores elegibles en la propiedad desde el diseñador de Visual Studio:
Fin de este pequeño tutorial de creación de controles para ASP.Net


Roy {aka. Foy}

Autor & Editor

Desarrallador y líder técnico, con experiencia en tecnologías Microsoft desde los tiempos del VB6 y el asp clásico hasta el .Net Core, pasando por COM+, javascript, angularjs, Ionic, xaml, cordova, MVC, Web Api, Sql Server, Oracle... . Ávido lector, apasionado programador.