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,


3 comentarios:

  1. Como recorrer un gridview para compararlo con un textbox cosa que si son iguales me mande un mensaje que ya existe ese dato y no se puede guardar por favor ojala me puedan ayudar

    ResponderEliminar
  2. Hola! Perdón la demora en responder. Para poder comparar los datos de un gridview contra un textbox, podés hacer lo siguiente:

    Recorrer los elementos de una columna del gridview e ir chequeando que el valor sea el mismo del textbox

    foreach(DataGridRow row in GridView1.Rows){
    if (TextBox1.Text == row.Cells["columnaAComparar"].ToString())
    lblMessage.Text = "Ese dato ya fue ingresado";
    break;
    }
    }

    Saludos,

    ResponderEliminar
  3. Buenas Tardes.

    Al usar el control, existe una forma para solo actualizar un elemento de esa lista?.

    Mi lista personalizada

    TITULO | Lista que despliega opciones (Dropdownlist)

    Ej.
    Area 1 | Fisica
    Qumica

    etc.

    La idea es actualizar los datos del Dropdownlist, de acuerdo a la área que seleccione

    Gracias

    ResponderEliminar