Custom MembershipProvider Y RoleProvider

El modelo de Proveedores desde su aparición con ASP.NET 2.0 ha sido un tema muy recurrente y se han escrito ríos de tinta sobre sus beneficios, pero ya sea porque realmente nos encontraremos en muchas ocasiones que los proveedores por defecto no cubren todas nuestras necesidades o porque hemos migrado una aplicación donde ya tenemos todos los datos o simplemente porque no tengo tanta imaginación, en este artículo mostraré como poder crear nuestro propio proveedor.

ASP.NET 2.0 ofrece soporte para el modelo de proveedores para diferentes servicios:

  • Membership
    • System.Web.Security.SqlMembershipProvider
    • System.Web.Security.ActiveDirectoryMembershipProvider
  • Roles
    • System.Web.Security.SqlRoleProvider
    • System.Web.Security.AuthorizationStoreRoleProvider
    • System.Web.Security.WindowsTokenRoleProvider
  • Profile
    • System.Web.Profile.SqlProfileProvider
  • SessionState
    • System.Web.SessionState.InProcSessionStateStore
    • System.Web.SessionState.OutOfProcSessionStateStore
    • System.Web.SessionState.SqlSessionStateStore
  • Configuration
    • System.Configuration.DPAPIProtectedConfigurationProvider
    • System.Configuartion.RSAProtectedConfigurationProvider
  • SiteMap
    • System.Web.XmlSiteMapProvider
  • WebEvents
    • System.Web.Management.EventLogWebEventProvider
    • System.Web.Management.SimpleMailWebEventProvider
    • System.Web.Management.SqlWebEventProvider
    • System.Web.Management.TemplatedMailWebEventProvider
    • System.Web.Management.WmiWebEventProvider
    • System.Web.Management.TraceWebEventProvider
  • WebParts
    • System.Web.UI.WebControls.WebParts.SqlPersonalizationProvider

La intención de este artículo no es profundizar en el modelo de proveedores sino aprovechar toda su potencia, imaginemos que tenemos una aplicación web que hemos migrado o que simplemente tiene que aprovechar los datos de otra aplicación, entonces crearemos nuestro proveedor basándonos en las clases MembershipProvider y RolProvider para que se adapte a nuestras necesidades.

Empezaremos con la base de datos en Access que hemos aprovechado de otra aplicación 😉

Como podéis observar simplemente tenemos una tabla de usuarios una de roles y una tabla intermedia de UsuariosPorRol.

Crearemos nuestro primer proveedor con la clase Usuarios que herede de MembershipProvider, que al ser una clase abstracta nos facilitara la manera de implementar un proveedor de este subsistema Membership.

No es necesario sobreescribir todos los métodos de esta clase, solo los que tengamos que utilizar posteriormente.

Por  ejemplo el método ValidateUser:

public override bool ValidateUser(

string username, string password){    bool userExists = false;    OleDbCommand command = new OleDbCommand();   try    {      command.Connection = connection;      command.CommandText = «SELECT IDUsuario FROM Usuarios Where Nombre=@Nombre AND Pass=@Pass»;      command.Parameters.AddWithValue(«@Nombre», username);      command.Parameters.AddWithValue(«@Pass», password);      command.Connection.Open();       OleDbDataReader rd = command.ExecuteReader();      if (rd.HasRows)         userExists = true;     }    Catch…

 

O CreateUser:

public override MembershipUser CreateUser(

string username, string password, string email,

string passwordQuestion, string passwordAnswer, bool isApproved,

object providerUserKey, out MembershipCreateStatus status){   MembershipUser newUser = null;   OleDbCommand command = new OleDbCommand();    try   {     command.Connection = connection;     command.CommandText = @»INSERT INTO Usuarios ( Nombre, Mail, Pass)                    VALUES (@Nombre, @Mail, @Pass )»;     command.Parameters.AddWithValue(«@Nombre», username);     command.Parameters.AddWithValue(«@Mail», email);     command.Parameters.AddWithValue(«@Pass», password);     command.Connection.Open();     command.ExecuteNonQuery();      newUser = new MembershipUser(«Usuarios», username, null, String.Empty, String.Empty,String.Empty, true, false, DateTime.Now,DateTime.Now, DateTime.Now, DateTime.Now,DateTime.Now);       status = MembershipCreateStatus.Success;  }  Catch…

La clase Roles que hereda de RoleProvider e implementaremos métodos como:

public override string[] GetAllRoles(){    OleDbCommand command = new OleDbCommand();    List<string> resultado = new List<string>();    try    {      command.Connection = connection;      command.CommandText = «SELECT Rol FROM Roles»;      command.Connection.Open();      OleDbDataReader rd = command.ExecuteReader();      while (rd.Read())         resultado.Add(rd.GetString(0));      return resultado.ToArray();    }    Catch…

Una vez que tenemos nuestros proveedores creados ya los podemos utilizar y para eso los  tenemos que definir en el web.config de nuestra aplicación.

<membership defaultProvider=«Usuarios«>  <providers>   <clear/><add name=«Usuarios» type=«Demo.Seguridad.Usuarios» connectionStringName=«MyProviderConnectionString» minRequiredNonalphanumericCharacters=«0» requiresQuestionAndAnswer=«false» enablePasswordReset=«true«/>  </providers>

</membership>

Definimos nuestro proveedor como proveedor por defecto y sus propiedades.

<roleManager enabled=«true« defaultProvider=«Roles«> <providers>  <clear/>  <add name=«Roles« connectionStringName=«MyProviderConnectionString« type=«Demo.Seguridad.Roles«/> </providers></roleManager>

Para probar nuestros proveedores crearemos una página de login con un control asp:Login, una página de registro para crear nuevos usuarios con un control asp:CreateUserWizard.

Y el proyecto funcionando se mostraría como

 

Para que podáis estudiar mejor el proyecto os lo podéis bajar desde: geeks.ms/…/entry67524.aspx

CrossPosting de http://mrubino.net

 

LoNetCamp da sus primeros pasos

El pasado 18 de Enero del 2008 fue definitivamente un gran día para la nueva historia del LoNetCamp.


Después de muchos preparativos y la convicción de sus promotores que la idea no se quedara en un simple intento, pudimos asistir a la primera reunión abierta del grupo.


La iniciativa a pasado por diferentes estados y por supuesto no esperábamos que tuviera tanta acogida la primera charla, la asistencia fue todo un éxito, unas treinta personas entre profesionales y estudiantes del IES Baix Camp contribuyeron a que la velada se cerrara con la convicción de que el grupo puede tener futuro en la Provincia para promover y facilitar la asimilación de todas las novedades que van surgiendo continuamente en este gran mundo del desarrollo de software.


 La charla transcurrió con fluidez y se trató de mostrar las entrañas de la plataforma de .NET para que en los próximos eventos podamos afrontar todas las novedades con los conocimientos suficientes de la filosofía de la tecnología .NET.


 Y como una imagen vale más que mil palabras…



 


Todas las Fotos en http://lonetcamp.com/Community/photos/eventos/category1057.aspx


Nos Vemos en la próxima.


CrossPosting http://lonetcamp.com


 


 

Primer Evento Oficial del Grupo en TARRAGONA

Primer Evento Oficial  !!!!



Introducción:
 
Con este evento pretendemos presentar el grupo de usuario de la provincia de Tarragona y aprovechar para charlar de la evolución de nuestros desarrollos y como .Net nos ha ayudado a resolver las nuevas necesidades.
 
Veremos como ha evolucionado esta plataforma y con que nuevas herramientas contaremos para este año.
 


Agenda:


19:00 Registro
19:15 Presentación del Grupo
19:45 La evolución de .Net ( Marc Rubiño )
20:45 Nuevos Eventos
21:00 Cierre

Fundació Universitat Rovira i Virgili (Mas Miarnau)
Av Onze de Setembre,112 (43203) Reus – TARRAGONA


Como Llegar…


Registro:  msevents.microsoft.com



 

DropDownList Color Picker

Quien no ha necesitado alguna vez poder echar mano de algún control para poder mostrar los colores del sistema y que los usuarios puedan personalizar su entorno.


Pues hoy vamos a retocar la presentación de un DropdonwList para mostrar el color de fondo con el color del registro.


Nuestro control se mostrara tal que así:


 



Para realizar esto solo necesitaremos un método.




private void CargarColores( DropDownList ddl )


    {


        int index = -1;


        if (ddl.SelectedIndex > 0)


            index = ddl.SelectedIndex;

 

        //Inicializamos los colores y mostramos el mensaje de seleccionar color.


        ddl.Items.Clear();


        ddl.Items.Add(«Color…»);

 

        foreach (int pos in Enum.GetValues(typeof(System.Drawing.KnownColor)))


        {


            string strnColor = Enum.GetName(typeof(System.Drawing.KnownColor), pos);


            System.Drawing.Color color = System.Drawing.Color.FromName(strnColor);

 

            if (!color.IsSystemColor)


            {


                ListItem item = new ListItem(color.Name, pos.ToString());


                item.Attributes.CssStyle.Add(HtmlTextWriterStyle.BackgroundColor, color.Name);


                ddl.Items.Add(item);


            }


        }

 

        //Si tenia indice lo seleccionamos.


        if (index > 0)


            ddl.SelectedIndex = index;


    }


Para obtener los colores del sistema contamos con la enumeración System.Drawing.KnownColor el cual lo recorreremos para obtener un objeto System.Drawing.Color  y poderlo utilizar para generar los items del Dropdownlist .


foreach (int pos in Enum.GetValues(typeof(System.Drawing.KnownColor)))


Para que solo nos muestre los colores compatibles y no los de los controles del sistema  if (!color.IsSystemColor).


Finalmente crearemos el Item y le añadiremos el estilo adecuado para mostrar el color de fondo.


item.Attributes.CssStyle.Add(HtmlTextWriterStyle.BackgroundColor, color.Name);


Para que podáis jugar un poco con la pruebas he creado un proyecto que podréis descargar.



 


Proyecto:   DropDownList Color Picker


Espero que sea de utilidad.


CrossPosting to http://lonetcamp.com


 

CrossTabs "Dinamic Pivot"

Si trabajáis normalmente con datos seguro que habéis necesitado crear alguna vez una consulta que devuelva una tabla con datos cruzados «Transformar filas en Columnas».


En SQL 2005 tenemos una función llamada PIVOT que intenta recuperar la funcionalidad de MS Access TRANSFORM pero nos encontramos con un gran inconveniente, tenemos que conocer el nombre de las nuevas columnas que queremos recuperar.


 Por ejemplo tenemos este código sacado de un artículo de Sebastian Contente…


SELECT Vendedor,isnull([Perfumes],0) as Cremas ,isnull([Desodorantes],0) as Desodorantes,
isnull([Cremas],0) as Perfumes
/*Select que define como se mostraran los tados y por que columna se agrupara (Vendedor)*/

FROM
(   ) po

/*Origen de los Datos*/
PIVOT
(
SUM(cantidad)
FOR Rubro IN
    ([Cremas] , [Perfumes] , [DEsodorantes])
    ) AS PVT


Podéis comprobar  que utiliza PIVOT para recuperar tres nuevas columnas por cada tipo de producto y  filtrado por vendedor sumando la cantidad a mostrar.


Pero Claro Tenemos que saber que existen estos registros para formar las nuevas columnas!!!


Que opciones tenemos para poder generar estas nuevas columnas dinámicamente?, bueno por Internet podemos encontrar varias formas y os recomiendo personalmente este artículo para sacarnos de dudas.



Este crack hasta ha hecho una aplicación para probar el rendimiento de las dos opciones y ha sacado esta conclusión.


Beginning performance test for crosstab techniques.


Please enter the # of iterations to perform:
75


Testing dynamic SQL crosstab procedure….
Result: 25 seconds.


Testing static SQL crosstab procedure….
— Result: 22 seconds.


Testing C# crosstab transformation….
Result: 8 seconds.


Testing complete.


Artículo completo…


Esta clarísimo cual es la forma más óptima para poder utilizar Crosstabs en nuestras aplicaciones y con un par de cambios podemos poner la función en nuestro DAL para reutilizarla fácilmente.


Bueno en definitiva si podéis pasaros por Jeff’s SQL Server Blog  que es totalmente recomendable.


Saludos.


CrossPosting de http://www.lonetcamp.com


 

ASP.NET AJAX TabControl – Tabs Optimizados

Bueno el hecho de decir que vamos a optimizar la carga de datos con un updatePanel es un poco contradictorio pero si lo utilizamos con un poco de cabeza y no solo para no ver la carga de la página podemos optimizar la utilización de este control.

La idea sería solo cargar la información de cada TabPanel dentro de un TabControl cuando sea necesario y no todo el control al cargar la página.

Para hacer esto tenemos que tener dos cosas claras.

  • Utilizaremos un updatePanel para actualizar cada TabPanel
  • Utilizaremos los Triggers del upDatePanel para capturar el evento ActiveTabChanged del TabContainer.

Que es eso de la colección de Triggers?

  • Habilitan que los eventos de controles fuera del UpdatePanel puedan actualizar su contenido.

Empezaremos ya con nuestro ejemplo.

  1.  Primero crearemos un nuevo sitio web con Asp.Net Ajax.
  2. Arrastraremos al formulario un nuevo control TabControl y le crearemos tres nuevos TabPanels.
  3. Al TabControl le Habilitamos el AutoPostBack = true para que lance sus eventos al servidor.
  4. Definimos un evento ActiveTabChanged del TabControl para capturar cada vez que se cambia de Tab.
  5. Dentro de cada TabPanel le introduciremos un UpdatePanel y dentro de el un label para hacer las pruebas.
  6. A cada uno de los UpdatePanels le añadimos un trigger para que se actualice con el evento ActiveTabChanged del TabControl que hemos configurado.

Ahora Empezaremos con el código.

Al cargar la página inicializamos los controles y cargamos el tab principal.

protected void Page_Load(object sender, EventArgs e)     {        lblTab1.Text = string.Empty;        lblTab2.Text = string.Empty;        lblTab3.Text = string.Empty;         if (!IsPostBack)        {            CargarTab(«TabPanel1»);        } 

    } 

 En el evento ActiveTabChange controlamos el nuevo tab y cargamos su contenido.

 protected void TabContainer1_ActiveTabChanged(object sender, EventArgs e){   CargarTab(((AjaxControlToolkit.TabContainer)sender).ActiveTab.ID); }

 

Finalmente tenemos un método que carga únicamente la información del tab que queremos mostrar.

private void CargarTab(string id)    {        switch (id)        {            default:                break;            case «TabPanel1»:                System.Threading.Thread.Sleep(500);                lblTab1.Text = » Datos Tab1 Actualizados…»;                break;            case «TabPanel2»:                System.Threading.Thread.Sleep(500);                lblTab2.Text = » Datos Tab2 Actualizados…»;                break;            case «TabPanel3»:                System.Threading.Thread.Sleep(500);                lblTab3.Text = » Datos Tab3 Actualizados…»;                break;        }    }

 

El resultado final sería que solo se cargaría la información del TabControl que estamos mostrando.

 

C# 3.0 y LINQ

Ya está disponible la nueva herramienta indispensable para los geeks de habla hispana.


 

¿Te interesa aprovechar todo lo nuevo que ofrece la versión 3.0 de C#? ¿Te gustaría saber que es todo lo que nos traerá  LinQ en el nuevo Visual Studio 2008 que saldrá en pocos meses? 

Pues el maestro OCTAVIO HERNÁNDEZ LEAL (Microsoft MCT y MSD, Microsoft MVP, y tutor de Campus MVP) nos obsequia con el primer libro es castellano sobre este tema y seguramente no solo en castellano [;)].


 



 


Cómpralo ahora por sólo 32,00 Euros. ( IVA y gastos de envío a España incluidos).


Lo encontrarás en las principales librerías españolas (FNAC, Casa del Libro, etc…) o puedes pedirlo directamente a Krasis en el teléfono 902 876 475 .


 


TOTALMENTE RECOMENDABLE


 


Otros libros de la Colección:



Os animo a todos que lo leáis porque realmente vale la pena.


 


Saludos.


 


 


 


 

October Conference 2007 Forever !!!

Después de estos dos días a tope con 12 ponentes y 20 charlas solo me queda decir una cosa. Impresionanteeee!!!!


Empezando con Hadi y Martin Lopez que se han currado muchísimo la organización de la conferencia han dejado muy difícil a los otros grupos superar el nivel de este encuentro.



  • Neal Ford con sus lenguajes dinámicos y Ruby on Rails nos enseña que hay vida mas allá de Microsoft y que todos somos programadores multilenguaje ( C#, javascript, XML, SQL,etc).

  • Michael Li Defenderse de los 8 ataques más comunes en ASP.Net y Páginas ASP.NET escalables.

  • El Guille con las novedades de VB 9.0 y LinQ ante los programadores del punto y coma.

  • José Manuel Alarcon No se encontraba del todo bien pero sacó fuerzas para poder terminar sus charlas «Esperemos que ya se encuentre mejor ;-)»

  • Dino Esposito Nos enseño que AJAX.NET es más que los updatePanel y que además no es oro todo lo que reluce.

  • Unai Zorrila con una MasterClass sobre Modelado de procesos con WF.

  • Martin Lopez  nos enseñó el mundo real del día a día con SharePoint.

  • Octavio Hernández  el Nº 1 en LinQ y lo nuevo en C# 3.0 nos demuestra lo que nos encontraremos en pocos meses.

  • David Salgado todo un Evangelista que nos demuestra como depurar en entornos de producción.

  • Hadi Hariri SQL CLR buenas y malas formas.

Definitivamente un gran nivelazo de las charlas y los ponentes. Ya estoy deseando que llegue el año que viene para ver que nuevos retos nos presentaran los chicos del grupo de usuarios de Málaga.


Enhorabuena y seguir así.


P.D.


Una cuantas fotos…


   


Más Fotos en…


 

El día después : MVP + TTT

No puedo hacer otra cosa que desde este rinconcito dar la gracias a todas esas personas que sin esperar nada a cambio aportan tanto a la comunidad y sin ellos no sería posible tener acceso a muchos de los recursos con los que hoy contamos.


 Por eso gracias Pep Lluis, Vicenç, Toni Recio, Javier Conesa, Fran Diaz, CSaky, Hadi Hariri, Ander, Jose Luis LaTorre, Ximo, Paco Marín, Iñigo herrero, David Salgado, Cristina Gonzalez, Salvador Ramos, Miguel Egea, David Darmona, Thempra, Alfonso Rodriguez…


Seguro que me dejo unos cuantos [:$] pero estoy seguro que no me lo tendréis en cuenta.


 Más información:



Y para que veáis algunas de las caras de las personas que he nombrado…


   


Para ver todas las Fotos aquí…


Otra cosa que no puedo dejar pasar es a estos dos monstruos, si, si los disfrazados de super Heroes !!!!


Aquí donde los veis son  Ricardo Varela ( MVP C#  ), Chema Alonso ( MVP de Seguridad ) y nos dieron la charla sobre seguridad más animada de las que he asistido nunca ^^.


No os perdáis el currículum de sesiones de estos dos MegaCracks. Momentus Ridiculous…


Saludos.


** CrossPosting desde www.lonetcamp.com **

Custom Control III

Para acabar con esta serie de artículos sobre como crear un control compuesto, veremos como personalizar el renderizado y poder comprobar en tiempo de diseño como quedara realmente nuestro control en la Página.


En los artículos anteriores vimos:



  1. Custom Control I : Como crear los controles secundarios y sus eventos.

  2. Custom Control II: Las Propiedades necesarias para personalizar nuestro control.

Ya tenemos nuestro control terminado y funcionando, pero personalmente me da mucha rabia esos controles que los arrastramos a nuestro formulario y solo te muestran el nombre y no te puedes hacer a la idea de como quedará ralmente en la página.


 


Me parece que el control desluce mucho y no nos ayuda a la hora de diseñar nuestra página.


Como podemos solucionar esto???


Muy sencillo, controlando el renderizado del control y sabiendo en cada momento lo que tenemos que pintar en la pantalla.

protected override void Render(HtmlTextWriter writer)
{
EnsureChildControls();

#region Titulo

writer.AddAttribute(HtmlTextWriterAttribute.Cellpadding, «0», false);
writer.AddAttribute(HtmlTextWriterAttribute.Cellspacing, «0», false);
writer.AddAttribute(HtmlTextWriterAttribute.Class, this.CssClass, false);
writer.RenderBeginTag(HtmlTextWriterTag.Table);
writer.RenderBeginTag(HtmlTextWriterTag.Tr);

writer.AddAttribute(HtmlTextWriterAttribute.Align, «Left», false);
writer.AddAttribute(HtmlTextWriterAttribute.Class, this.CssAnterior, false);
writer.RenderBeginTag(HtmlTextWriterTag.Td);

if (string.IsNullOrEmpty(this.ImgAnterior))
lAnterior.RenderControl(writer);
else
ImAnterior.RenderControl(writer);

writer.RenderEndTag();

writer.AddAttribute(HtmlTextWriterAttribute.Align, «Center», false);
writer.AddAttribute(HtmlTextWriterAttribute.Class, this.CssTitulo, false);
writer.RenderBeginTag(HtmlTextWriterTag.Td);
lTitulo.RenderControl(writer);
writer.RenderEndTag();

writer.AddAttribute(HtmlTextWriterAttribute.Align, «Right», false);
writer.AddAttribute(HtmlTextWriterAttribute.Class, this.CssSiguiente, false);
writer.RenderBeginTag(HtmlTextWriterTag.Td);

if (string.IsNullOrEmpty(this.ImgAnterior))
lSiguiente.RenderControl(writer);
else
ImSiguiente.RenderControl(writer);

writer.RenderEndTag();
writer.RenderEndTag();

writer.RenderBeginTag(HtmlTextWriterTag.Tr);

#endregion Titulo

#region Calendario

writer.AddAttribute(HtmlTextWriterAttribute.Colspan, «3», false);
writer.RenderBeginTag(HtmlTextWriterTag.Td);

writer.AddAttribute(HtmlTextWriterAttribute.Class, this.CssCeldaCalendario, false);
writer.RenderBeginTag(HtmlTextWriterTag.Table);
int col = this.Calendarios / this.Filas;
int mes = 0;
int posCal = 0;

for (int y = 0; y < this.Filas; y++)
{
writer.RenderBeginTag(HtmlTextWriterTag.Tr);
for (int x = 0; x < col; x++, mes++, posCal++)
{
writer.RenderBeginTag(HtmlTextWriterTag.Td);
LCalendarios[posCal].RenderControl(writer);
writer.RenderEndTag();
}
writer.RenderEndTag();
}

writer.RenderEndTag();
writer.RenderEndTag();

#endregion Calendario

#region Pie

writer.RenderBeginTag(HtmlTextWriterTag.Tr);
writer.AddAttribute(HtmlTextWriterAttribute.Colspan, «3», false);
writer.AddAttribute(HtmlTextWriterAttribute.Class, this.CssPie, false);
writer.RenderBeginTag(HtmlTextWriterTag.Td);
writer.RenderEndTag();
writer.RenderEndTag();

writer.RenderEndTag();
writer.RenderEndTag();

#endregion Pie

}


Estudiaremos es te código por partes.




  • Lo primero que tenemos que hacer es asegurarnos que los controles secundarios se han creado para poder utilizarlos.



    EnsureChildControls();


  • Utilizaremos el HtmlTextWriter para crear la estructura del control ( Una tabla, filas y celdas para poder colocar los calendarios en su sitio)


    writer.AddAttribute(HtmlTextWriterAttribute.Cellpadding, «0», false);
    writer.AddAttribute(HtmlTextWriterAttribute.Cellspacing, «0», false);
    writer.AddAttribute(HtmlTextWriterAttribute.Class, this.CssClass, false);
    writer.RenderBeginTag(HtmlTextWriterTag.Table);
    writer.RenderBeginTag(HtmlTextWriterTag.Tr);

    writer.AddAttribute(HtmlTextWriterAttribute.Align, «Left», false);
    writer.AddAttribute(HtmlTextWriterAttribute.Class, this.CssAnterior, false);
    writer.RenderBeginTag(HtmlTextWriterTag.Td);




  • Pintaremos los calendarios dependiendo de la cantidad de filas que tengamos configurado


    #region Calendario

    writer.AddAttribute(HtmlTextWriterAttribute.Colspan, «3», false);
    writer.RenderBeginTag(HtmlTextWriterTag.Td);

    writer.AddAttribute(HtmlTextWriterAttribute.Class, this.CssCeldaCalendario, false);
    writer.RenderBeginTag(HtmlTextWriterTag.Table);
    int col = this.Calendarios / this.Filas;
    int mes = 0;
    int posCal = 0;

    for (int y = 0; y < this.Filas; y++)
    {
        writer.RenderBeginTag(HtmlTextWriterTag.Tr);
        for (int x = 0; x < col; x++, mes++, posCal++)
        {
            writer.RenderBeginTag(HtmlTextWriterTag.Td);
            LCalendarios[posCal].RenderControl(writer);
            writer.RenderEndTag();
        }
        writer.RenderEndTag();
    }

    writer.RenderEndTag();
    writer.RenderEndTag();

    #endregion Calendario


Después de controlar el renderizado de nuestro control podremos disfrutar de todo su potencial en tiempo de diseño y todas las modificaciones que hagamos en sus propiedades se reflejarán automáticamente en la pantalla.


 


 


Bueno yo creo que ya tenemos el control bastante decente no?, se que podría tener más funcionalidades y muchísimo más vistoso, pero como ejemplo de como crear un control compuesto me parece suficiente ;-).


Si queréis Trastear el proyecto os lo podéis bajar gratuitamente y si tenéis dudas me lo podéis comentar sin problemas.


Espero veros por estos barrios.


  Proyecto CustomCalendar.


User Control I    –    User Control II  –  User Control III


** CrossPosting Desde http://www.lonetcamp.com ***