Controles Repeater anidados en listados ASP.NET

Es habitual al desarrollar aplicaciones web con ASP.NET, tener que utilizar controles Repeater para mostrar el contenido de un listado. Se puede utilizar para mostrar un listado de noticias, el contenido de un carro de la compra, o simplemente un conjunto de enlaces. El funcionamiento de este control es muy sencillo, y se basa en asignar al control una colección de datos que podemos haber obtenido de cualquier fuente, como un archivo XML, o una base de datos. Sin embargo hay situaciones algo más complejas, en las que necesitamos mostrar listados anidados, es decir, listados de elementos que a su vez también son listados. Esto es bastante frecuente en la realidad, y se puede apreciar por ejemplo, en la necesidad de mostrar un listado de clientes con los libros que tienen alquilados, o en un listado de discos con las canciones que los componen.

Como he comentado, el funcionamiento básico del control Repeater es muy sencillo y la vez muy potente y flexible. Podemos configurar el control, desde su lado HTML, mediante la utilización de las distintas plantillas que acepta para cada elemento del listado: encabezado, pie, separadores, y elementos que lo forma, pudiendo diferenciar incluso entre elementos sucesivos mediante ItemTemplate y AlternatingItemTemplate. Por otra parte también disponemos de la opción de controlar su comportamiento mediante la utilización de los eventos. En nuestro caso vamos a aprovechar ambas posibilidades para conseguir el resultado que queremos.

Para nuestro ejemplo vamos a suponer que queremos mostrar un listado de discos y canciones. Por manterner sencillo el ejemplo y centrarnos en lo que nos ocupa, vamos a olvidarnos de dónde obtenemos los datos reales de discos y canciones, y vamos a suponer que tenemos sus nombres disponibles en un array de strings.

Vamos a comenzar con el caso sencillo, mostrando el listado de discos.

<html>
<head>
<script runat="server" language="C#">
void Page_Load(Object s, EventArgs e) {
   string[] discos = new string[]{"Purple Rain","Wish","Graffiti Bridge","Vertigo"};
   rDiscos.DataSource = discos;
   rDiscos.DataBind();
}
</script>
</head>
 
<body>
<form runat="server">
<asp:Repeater Runat="server" ID="rDiscos">
<ItemTemplate>
   <dl>
      <dt><%#Container.DataItem%></dt>
   </dl>
</ItemTemplate>
</asp:Repeater>
</form>
</body>
</html>

Como véis, este caso es realmente sencillo. Lo único que hemos tenido que hacer ha sido asignar el array de discos a la propiedad DataSource del Repeater. En la parte HTML, para mostrar el nombre del disco hemos utilizado directamente <%#Container.DataItem%>, aunque normalmente esto será algo más complicado y requerirá utilizar algún cast o DataBinder.Eval.

Vayamos ahora con el ejemplo completo.

<html>
<head>
<script runat="server" language="C#">
void Page_Load(Object s, EventArgs e) {
   string[] discos = new string[]{"Purple Rain","Wish","Graffiti Bridge","Vertigo"};
   rDiscos.DataSource = discos;
   rDiscos.DataBind();
}
 
private void rCanciones_ItemDataBound(object sender, System.Web.UI.WebControls.RepeaterItemEventArgs e)
{
   if(e.Item.ItemType == ListItemType.Item || 
      e.Item.ItemType == ListItemType.AlternatingItem)
   {
      string disco = (string)e.Item.DataItem;
      string[] canciones = new string[]{"canción 1","canción 2","canción 3"};
 
      Repeater rCanciones = (Repeater)e.Item.FindControl("rCanciones");
 
      rCanciones.DataSource = canciones;
      rCanciones.DataBind();
   }
}
</script>
</head>
 
<body>
<form runat="server">
<asp:Repeater Runat="server" ID="rDiscos" OnItemDataBound="rCanciones_ItemDataBound">
<ItemTemplate>
   <dl>
      <dt><%#Container.DataItem%></dt>
      <dd>
      <asp:repeater Runat="server" ID="rCanciones">
         <ItemTemplate><%#Container.DataItem%></ItemTemplate>
         <SeparatorTemplate>, </SeparatorTemplate>
      </asp:repeater>
      </dd>
   </dl>
</ItemTemplate>
</asp:Repeater>
</form>
</body>
</html>

Empecemos por la parte correspondiente al código HTML. Lo que he hecho ha sido anidar los repeater, creando un nuevo control dentro de la plantilla ItemTemplate. Sin embargo, esto no implica que podamos acceder al control directamente desde código con su nombre, rCanciones en nuestro caso. Esto es así debido a que no tiene porqué existir un único control, de hecho, existirá uno por cada elemento del listado, y además, estos controles empezarán a existir tras hacer el DataBind, no antes, es decir, que existirán únicamente en tiempo de ejecución.

Bien, aparte de crear este nuevo repeater, he añadido un atributo OnItemDataBound al repeater rDiscos. Este evento se dispara cada vez que se parsea un elemento del repeater. Ya dentro del código del método, el primer punto importante es el if que comprueba el tipo de item que se está parseando en el repeater. En nuestro caso únicamente nos fijaremos en los casos en los que se esté parseando un elemento real, ni la cabecera, ni el pie, ni los separadores nos interesan. Esta comprobación la realizamos mediante el evento que llega al método, perteneciente a la clase RepeaterItemEventArgs. Este evento tiene una propiedad Item que referencia directamente al item, proporcionándonos su tipo, el valor que contiene, y el código HTML especificado.

Una vez que estamos dentro del método y sabemos que estamos parseando un elemento del listado, el segundo punto importante es localizar dentro del HTML del elemento, el repeater rCanciones. Como el elemento Item que estamos parseando hereda de System.Web.UI.Conrol, disponemos del método FindControl para buscar dentro de él un control con el nombre que queramos, en nuestro caso, rCanciones. El código resultante sería (Repeater)e.Item.FindControl("rCanciones"), en el que aparte del FindControl, hacemos un cast a Repeater del resultado obtenido. Tras esto queda únicamente asignar la lista de canciones al DataSource y hacer el DataBind.

Es importante entender, que con esto no hemos localizado en realidad el repeater que hemos escrito dentro del HTML de la página, sino uno que se ha generado, con ese mismo nombre y características, en tiempo de ejecución dentro del elemento de listado actual. Por lo tanto las sucesivas veces que se ejecute este código, una vez para cada disco, se estará ejecutando sobre diferentes controles Repeater.

Twitter Digg Delicious Stumbleupon Technorati Facebook Email

3 Respuestas para “Controles Repeater anidados en listados ASP.NET”

  1. Gracias por el TIP, me ayudo bastante

  2. Muy bueno. Me ayudo mucho.

    Gracias.

  3. Muy buen ejemplo. Gracias por compartirnos tus conocimientos y así poder orientarnos!

    Tengo una consulta:
    en caso de canciones las deseo mostrar en controles, por ejemplo RadioButton, cómo podría hacer que se seleccione 1 canción por cada disco y ya no permita que se seleccionen todos a su vez