lunes, 30 de enero de 2012

ASP.NET – Como establecer un tema (theme) en tu proyecto y hacer uso con máscaras y hojas de estilos

Para empezar si no estamos al tanto para que sirve un tema en asp.net, se puede decir que los temas son una colección de estilos y propiedades que definen la apariencia de las páginas y controles de tu sitio web. Pueden incluir archivos de máscaras (skins) los cuales definen los valores de las propiedades para los controles ASP.NET. También pueden incluir archivos de hojas de estilos (CSS) que van a definir colores, gráficos, tamaños y posicionamiento de los controles y por sobre todo la apariencia del sitio. Son útiles además, debido a que es posible teniendo un tema ya aplicado, poder cambiar el aspecto de todo el sitio de forma muy sencilla.
¿Cómo crear un tema?
Para poder crear un tema es necesario agregar la carpeta app_themes a nuestro sitio web. Para esto haremos click derecho sobre el nombre de nuestro sitio y seleccionamos “agregar”, “agregar carpeta ASP.NET” y luego “Tema” como se muestra en la imagen de abajo.Source file

Agregar carpate de temas














Una vez realizado esto aparecerá la carpeta App_Themes sobre nuestro proyecto y nos pedirá que le asignemos un nombre a nuestro tema. En este caso yo le puse de nombre general. Es posible crear varios temas para cambiar por dar un ejemplo el color del sitio para una estación del año en particular. Entonces teniendo 2 temas, con diferentes colores simplemente para realizar esto hay que indicarle al sitio que utilice el otro tema.

¿Cómo agregar las máscaras (skins) y las hojas de estilos (CSS) al tema?
Hacemos click derecho sobre el nombre del tema (General) y seleccionamos la opción “agregar”, “nuevo elemento” y sobre la lista de elementos seleccionamos archivo de máscara. Le podemos dar de nombre General.skin para continuar con la misma línea de nombres originales. Va a aparecer una pantalla como la siguiente:

Agregar máscaras















En esa pantalla se muestra un ejemplo de cómo crear una máscara para un control por medio del SkinId y sin el SkinId o como también se llama, máscaras por defecto y máscaras con nombre.

Luego vamos a crear un estilo y para esto al igual que para agregar la máscara, hacemos click derecho sobre el tema (General) y seleccionamos la opción “agregar”, “nuevo elemento” y esta vez de la lista de elementos seleccionamos hoja de estilos y le ponemos el nombre que queramos.
Vamos a crear en el sitio un skin para los controles TextBox y Label. Para esto escribiremos lo siguiente dentro de la máscara:
Source file
<asp:Label runat="server" skinid="lblGeneral" cssclass="Label" />
<asp:TextBox runat="server" skinid="txtGeneral" cssclass="TextBox"/>

Luego en la hoja de estilos vamos a crear los estilos para las CssClass que definimos para los controles Label y TextBox:
Source file
.Label
{
 font-size: 11px;
 font-family: Tahoma;
 color: Red;
}

.TextBox
{
 font-size: 11px;
 font-family: Tahoma;
 color: Red;
 background-color:Black;
 border: 1px solid white;
}

Para finalizar y poder hacer que nuestra página reconozca las máscaras del tema, deberemos agregar Theme="General" en la directiva de la página . De esa forma todos los SkinId que agreguemos a los controles de tipo Label y TextBox  con el nombre lblGeneral y txtGeneral respectivamente tomarán el estilo agregado en el tema.
Voy a pegar el html de la página que cree con estos 2 controles para que se vea un poco mejor:
Source file
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="WebForm1.aspx.cs" Inherits="WebApplication3.WebForm1"
    Theme="General" %>

<!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></title>
</head>
<body style="background-color:Black">
    <form id="form1" runat="server">
    <h2 style="color:White"> Ejemplo de uso de temas en el sitio</h2>
    <hr />
    <div>
        <asp:Label ID="Label1" runat="server" Text="Ejemplo de skin a Label" SkinID="lblGeneral"></asp:Label>
        <asp:TextBox ID="TextBox1" runat="server" Text="Ejemplo de skin a Textbox" SkinID="txtGeneral"></asp:TextBox>
    </div>
    </form>
</body>
</html>

Ahora voy a poner una imagen de cómo se ve la página creada con ese código:







¿Cómo indicarle al sitio que el tema creado será utilizado en todo el proyecto?

En el ejemplo anterior el tema solo funcionaba si agregábamos en la directiva de la página Theme="General".  Ahora veremos como hacer para que el tema pueda aplicarse en todo el sitio. Para esto hay que abrir el archivo web.config e indicar dentro del tag Source file<system.web></system.web>
lo siguiente:

Source file
<pages theme="General">
</pages>

Si el tag ya existe entonces bastará con agregarle theme=”General”. De esta forma solo modificando el archivo web.config se podrá hacer uso de los SkinId en todo el sitio sin necesidad de indicar en la directiva de cada página el tema que va a utilizar.

Fin de la entrada.

Dejo el código para que descarguen el ejemplo.




Saludos.

domingo, 22 de enero de 2012

ASP.NET – Recorrer Repeater y obtener valores de diversos controles

El control repeater de ASP.NET es un contenedor enlazado a datos que permite crear listas personalizadas. Este control no posee una apariencia propia, con lo cual según la plantilla que se realice será como se mostrará luego en forma de listas. Las listas que son posibles de crear con este control son: diseño de tabla, delimitada por comas y con formato XML.
El aspecto del repeater así como viene cuando lo arrastramos a nuestra página es el siguiente:
  1. <asp:Repeater ID="Repeater1" runat="server">
  2. </asp:Repeater>
Vamos a hacer un ejemplo con el diseño de tablas para saber de lo que estamos hablando.

El ejemplo que vamos a realizar será cargar un repeater con  datos de clientes. Para esto crearemos las clases que nos harán falta junto con sus métodos para cargar el control.
Los atributos de los clientes serán:
Codigo
NombreFantasia
RazonSocial
Telefono
Direccion
CUIT
DadoDeBaja

Dentro del repeater podremos agregar tanto controles HTML, como ASPX. Estos se repetirán tantas veces como elementos vengan en el datasource del control.
Para poder armar la apariencia que le queremos dar al control, vamos a crear 2 tablas. La primera será para la cabecera del control, que se incluirá dentro de las etiquetas <HeaderTemplate></HeaderTemplate> y la segunda que servirá para mostrar el contenido del Repeter y se incluirá dentro de las etiquetas <ItemTemplate></ItemTemplate>.

La tabla que incluiremos en el HeaderTemplate es la siguiente:

<table>
   <tr>
      <th id="colEliminar" style="width: 20px;">
      </th>
      <th style="width: 90px;">
         Nombre Fantasia
      </th>
      <th style="width: 90px;">
         Razón Social
      </th>
      <th style="width: 50px;">
         Teléfono
      </th>
      <th style="width: 150px;">
         Dirección
      </th>
      <th style="width: 70px;">
         Cuit
      </th>
      <th id="check" style="width: 20px;">
         Baja
      </th>
   </tr>

La tabla que incluiremos en el ItemTemplate es la siguiente:

<tr>
   <td>
      <asp:ImageButton ID="imgBtnEliminar" runat="server"
         CommandName="Eliminar" CommandArgument='<%#Eval("IdCliente")%>' />
   </td>
   <td>
      <%#DataBinder.Eval(Container.DataItem, "NombreFantasia")%>
   </td>
   <td>
      <%#DataBinder.Eval(Container.DataItem,"RazonSocial") %>
   </td>
   <td>
      <%#DataBinder.Eval(Container.DataItem,"Telefono") %>
   </td>
   <td>
      <%#DataBinder.Eval(Container.DataItem,"Direccion") %>
   </td>
   <td>
      <%#DataBinder.Eval(Container.DataItem,"Cuit") %>
   </td>
   <td align="center">
      <asp:CheckBox ID="chkDadoDeBaja" runat="server" Enabled="false" Checked='<%#DataBinder.Eval(Container.DataItem,"DadoDeBaja") %>' />
   </td>
</tr>

Notese que no cerré la etiqueta <table> y esto es porque luego agregaremos la etiqueta <FooterTemplate></FooterTemplate> y dentro de esta irá el </table> de esta forma:


<FooterTemplate>
</table>
</FooterTemplate>


De esta forma nuestro Repeater quedará así:

<asp:Repeater ID="rptClientes" runat="server" 
            onitemcommand="rptClientes_ItemCommand" 
            onitemdatabound="rptClientes_ItemDataBound">
            <HeaderTemplate>
                <table>
                    <tr>
                        <th id="colEliminar" style="width: 20px;">
                        </th>
                        <th style="width: 90px;">
                            Nombre Fantasia
                        </th>
                        <th style="width: 90px;">
                            Razón Social
                        </th>
                        <th style="width: 50px;">
                            Teléfono
                        </th>
                        <th style="width: 150px;">
                            Dirección
                        </th>
                        <th style="width: 70px;">
                            Cuit
                        </th>
                        <th id="check" style="width: 20px;">
                            Baja
                        </th>
                    </tr>
            </HeaderTemplate>
            <ItemTemplate>
                <tr>
                    <td>
                        <asp:ImageButton ID="imgBtnEliminar" runat="server"
                            CommandName="Eliminar" CommandArgument='<%#Eval("IdCliente")%>' />
                    </td>
                    <td>
                        <%#DataBinder.Eval(Container.DataItem, "NombreFantasia")%>
                    </td>
                    <td>
                        <%#DataBinder.Eval(Container.DataItem,"RazonSocial") %>
                    </td>
                    <td>
                        <%#DataBinder.Eval(Container.DataItem,"Telefono") %>
                    </td>
                    <td>
                        <%#DataBinder.Eval(Container.DataItem,"Direccion") %>
                    </td>
                    <td>
                        <%#DataBinder.Eval(Container.DataItem,"Cuit") %>
                    </td>
                    <td align="center">
                        <asp:CheckBox ID="chkDadoDeBaja" runat="server" Enabled="false" Checked='<%#DataBinder.Eval(Container.DataItem,"DadoDeBaja") %>' />
                    </td>
                </tr>
            </ItemTemplate>
            <FooterTemplate>
                </table>
            </FooterTemplate>
        </asp:Repeater>

Ahí quedó listo nuestro código en la página aspx

Ahora vamos al código c# en la página RecorrerRepeater.aspx.cs:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using Negocios;
using System.Data;

namespace RecorrerRepeater
{
    public partial class RecorrerRepeater : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {

        }

        protected void btnCargarRepeater_Click(object sender, EventArgs e)
        {
            try
            {

            Clientes_N unClienteN = new Clientes_N();
            DataTable dt = new DataTable();
            string sError = "";
            sError = unClienteN.Buscar_Todos(ref dt);

            if (!string.IsNullOrEmpty(sError)) throw new Exception(sError);

            if (dt.Rows.Count > 0)
            {
                rptClientes.DataSource = dt;
                rptClientes.DataBind();
            }
            }
            catch (Exception ex)
            {
                string msg = "<script type='text/javascript'>alert('" + ex.Message + "');</script>";
                Page.ClientScript.RegisterClientScriptBlock(GetType(), "Error", msg);
            }
        }
    }
}

Dentro de nuestro código se puede ver que hacemos referencia a una clase llamada Clientes_N, esta clase está definida en otro proyecto al que le dimos el nombre de Negocios para hacer una separación en capas. Veamos que arriba del código está el using a Negocios.

Vamos a definir la clase Clientes_N para ver lo que hace:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Datos;
using System.Data;

namespace Negocios
{
    public class Clientes_N
    {
        Clientes_D uncliente_D = new Clientes_D();

        public string Buscar_Todos(ref DataTable pS_dt)
        {
            return uncliente_D.Buscar_Todos(ref pS_dt);
        }
    }
}

Esta clase como se puede ver lo que hace es llamar a un método de otra clase llamada Clientes_D de otro proyecto denominado Datos. Al igual que en el caso anterior, se encuentra el using al proyecto de Datos.

Clase Clientes_D:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Data.SqlClient;

namespace Datos
{
    public class Clientes_D
    {
        string sqlStr;
        string sError;
        static string StrCnn = "data source=MLLARIN-NB\\SQL2008;initial catalog=Repeater;User Id=sa;password=sa;Trusted_Connection=False";

        public string Buscar_Todos(ref DataTable pS_dt)
        {
            try
            {
                SqlConnection conn = new SqlConnection(StrCnn);
                DataSet ds = new DataSet();

                conn.ConnectionString = StrCnn;
                SqlCommand comm = new SqlCommand("Clientes_Buscar_Todos", conn);

                comm.CommandTimeout = 600;
                conn.Open();

                SqlDataAdapter da = new SqlDataAdapter(comm);
                da.Fill(ds);
                pS_dt = ds.Tables[0];

                conn.Close();
                conn = null;
                comm.Dispose();
                return "";
            }
            catch (System.Exception ex)
            {
                return ex.Message;
                throw;
            }
        }
    }
}

Ahora que tenemos todo el código podremos ver al ejecutar nuestro código algo de la siguiente forma:
















Ahora, para poder acceder a los controles que se encuentran dentro del Repeater para por ejemplo:

-          Poner un mensaje personalizado en el ImageButton para eliminar.
-          Poder encontrar que cliente está dado de baja, obteniendo el valor del checkbox.
-          Recuperar el Nombre de Fantasía de un cliente.
-          Cambiar la imagen del ImageButton.

 Veamos cómo hacer esto:

El control Repeater tiene una serie de eventos con los que es posible detectar varias cosas.
En principio para poder hacer los 4 puntos que marcamos vamos a ver los eventos ItemDataBound e ItemCommand.
El siguiente código me servirá para poder cambiarle la imagen al ImageButton y poder definir mensajes personalizados al momento de ser presionado. Como mensaje personalizado le pondremos que pregunte si está seguro que desea eliminar al cliente: “Nombre de Fantasía”, donde el Nombre de Fantasía lo obtendremos del origen de datos.


protected void rptClientes_ItemDataBound(object sender, RepeaterItemEventArgs e)
        {
            RepeaterItem item = e.Item; // elemento del Repeater

            if (item.ItemType == ListItemType.AlternatingItem || item.ItemType == ListItemType.Item)
            {
                ImageButton imgBtnEliminar = (ImageButton)item.FindControl("imgBtnEliminar"); // obtenemos el control.
                // Como todavía no tiene definido el nombre de fantasía en el control, debemos acceder a este por medio de este código.
                string NombreFantasia = ((System.Data.DataRowView)(item.DataItem)).Row.ItemArray[1].ToString(); // obtenemos el control.

                CheckBox chkDadoDeBaja = (CheckBox)item.FindControl("chkDadoDeBaja"); // obtenemos el control checkbox.

                // Detectamos cuando el cliente no se encuentra eliminado, entonces mostramos la imágen para eliminar.
                if (!chkDadoDeBaja.Checked)
                {
                    imgBtnEliminar.Visible = true; // le indico al botón que sea visible.
                    // acá agregamos el evento OnClientClick y le indicamos el mensaje que queremos aparezca cuando se haga clic con el 
                    // mouse sobre este elemento
                    imgBtnEliminar.OnClientClick = "return confirm('Esta seguro que desea eliminar al cliente: " + NombreFantasia + " ?')";
                    imgBtnEliminar.ToolTip = "Eliminar";
                    // Cambiamos la imagen.
                    imgBtnEliminar.ImageUrl = "~/Images/Eliminar.png";
                }
                else
                {
                    imgBtnEliminar.Visible = false; // le indico al botón que este oculto.
                }
            }
        }

Los 4 puntos los pudimos resolver solo con el evento ItemDataBound. Ahora veamos el evento ItemCommand.

protected void rptClientes_ItemCommand(object source, RepeaterCommandEventArgs e)
        {
            if (e.CommandName == "Eliminar")
            {
                try
                {
                    // Podriamos crear un método para eliminar los clientes
                    // El elemento e.CommandArgument.ToString() me trae el CommandArgument definido en el código html de
                    // la página aspx. En nuestro código guardamos el IdCliente, con lo cual lo podríamos utilizar para
                    // eliminar el cliente seleccionado.

                }
                catch (Exception ex)
                {
                    string msg = "<script type='text/javascript'>alert('" + ex.Message + "');</script>";
                    Page.ClientScript.RegisterClientScriptBlock(GetType(), "Error", msg);
                }
            }
        }

Con esto creo que terminamos con lo propuesto en esta entrada.

Les dejo el código para su descarga: Descargar

Saludos,