21
Control Repeater ASP.NET El control Repeater de ASP .NET nos permite crear listas de datos aplicando una plantilla que se repetirá para todos los elementos mostrados. Este control resulta muy útil cuando queremos una mejor personalización de los datos o cuando no requerimos de tanta funcionalidad como la proporcionada por el GridView. A continuación veremos un ejemplo de cómo podemos utilizar este control y los resultados que nos proporciona. Comenzaremos mostrando la base de datos que vamos a utilizar para este ejemplo: Como podemos ver se trata de una base de datos muy sencilla que no requiere mucha explicación, tenemos una tabla de películas que tiene su identificador, el nombre de la película y el año de la película. Otra tabla génerosque contiene el identificador y el nombre del género. Por último, está la tabla pelicula_genero que relaciona la película con el género al que pertenece. En este caso se ha supuesto que una película puede pertenecer a varios géneros a la vez. Comencemos con el código ASP, lo primero que vamos a hacer es añadir un control Repeater y un controlSqlDataSource a nuestra página, además los enlazaremos quedando el siguiente código: 1. asp:repeater ID="Repeater1" runat="server" DataSourceID="SqlDataSourcePeliculas"> 2. </asp:repeater> 3. 4. <asp:SqlDataSource ID="SqlDataSourcePeliculas" runat="server"> 5. </asp:SqlDataSource> A continuación configuramos el SqlDataSource, seleccionamos la base de datos que hemos creado anteriormente. Cuando nos pregunte que datos queremos recuperar, seleccionamos de la tablapelículas el nombre y el año y continuamos hasta la finalización del asistente. El Repeater es un control que no se puede editar visualmente, así que los siguientes pasos los tendremos que hacer desde la edición de código. Dentro de las etiquetas del control escribimos lo siguiente:

Control Repeater ASP

Embed Size (px)

Citation preview

Control Repeater ASP.NET

El control Repeater de ASP .NET nos permite crear listas de datos aplicando una plantilla que se repetirá para todos los elementos mostrados. Este control resulta muy útil cuando queremos una mejor personalización de los datos o cuando no requerimos de tanta funcionalidad como la proporcionada por el GridView.

A continuación veremos un ejemplo de cómo podemos utilizar este control y los resultados que nos proporciona. Comenzaremos mostrando la base de datos que vamos a utilizar para este ejemplo:

Como podemos ver se trata de una base de datos muy sencilla que no requiere mucha explicación, tenemos una tabla de películas que tiene su identificador, el nombre de la película y el año de la película. Otra tabla génerosque contiene el identificador y el nombre del género. Por último, está la tabla pelicula_genero que relaciona la película con el género al que pertenece. En este caso se ha supuesto que una película puede pertenecer a varios géneros a la vez.

Comencemos con el código ASP, lo primero que vamos a hacer es añadir un control Repeater y un controlSqlDataSource a nuestra página, además los enlazaremos quedando el siguiente código:

1. asp:repeater ID="Repeater1" runat="server" DataSourceID="SqlDataSourcePeliculas">  2. </asp:repeater>  3.   4. <asp:SqlDataSource ID="SqlDataSourcePeliculas" runat="server">  5. </asp:SqlDataSource> 

A continuación configuramos el SqlDataSource, seleccionamos la base de datos que hemos creado anteriormente. Cuando nos pregunte que datos queremos recuperar, seleccionamos de la tablapelículas el nombre y el año y continuamos hasta la finalización del asistente. El Repeater es un control que no se puede editar visualmente, así que los siguientes pasos los tendremos que hacer desde la edición de código. Dentro de las etiquetas del control escribimos lo siguiente:

1. <asp:repeater ID="Repeater1" runat="server" DataSourceID="SqlDataSourcePeliculas">  2.   <HeaderTemplate>  3.     <ul>  4.   </HeaderTemplate>  5.   6.   <ItemTemplate>  7.     <li>  8.       <%# DataBinder.Eval(Container.DataItem, "titulo") %>   9.       (<%# DataBinder.Eval(Container.DataItem, "anyo") %>)  10.     </li>  11.   </ItemTemplate>  12.   13.   <FooterTemplate>  

14.     </ul>  15.   </FooterTemplate>  16. </asp:repeater>  

El código HTML o ASP que encerremos entre las etiquetas <HeaderTemplate></HeaderTemplate> se ejecutará una vez y renderizará en pantalla lo que contenga. En nuestro caso la etiqueta de apertura de una lista, estás etiquetas se suelen usar para poner una cabecera a los datos que vienen a continuación. Como se puede imaginar el código de las etiquetas<FooterTemplate></FooterTemplate> tendrán el mismo comportamiento que elHeaderTemplate, pero en esa ocasión se utilizará para el pie de los datos. En nuestro caso cerrar la lista. Por último nos queda la etiqueta ItemTemplate, lo que aparezca entre ella se renderizará una vez por cada elemento que contenga el resultado del DataSource que le hemos asociado.

La línea, DataBinder.Eval(Container.DataItem, "titulo") se encarga de recuperar del DataSource asociado el ítem con la etiqueta título. Por lo tanto en el ejemplo deveolverá el título de la película y el año de esta. Hay que tener en cuenta que tanto las secciones HeaderTemplate, comoFooterTemplate se ejecutarán aunque el DataSource asociado no recupere ningún dato, por el contrario la sección ItemTemplate únicamente se ejecutará si existen datos.

El resultado que veremos por pantalla, será el siguiente:

Ahora vayamos un paso más lejos, supongamos que queremos organizar todas las películas que tenemos según su género. Lo que tendríamos que hacer es seleccionar todos los géneros y después todas las películas pertenecientes a ese género. La forma de hacerlo será usando un Repeater anidado dentro de otro. Pasemos a ver cómo nos queda el código en esta ocasión:

1. <asp:repeater ID="RepeaterGeneros" runat="server" DataSourceID="SqlDataSourceGeneros"   2.   onitemdatabound="RepeaterGeneros_ItemDataBound">  3.   <ItemTemplate>  4.     <h2><%# DataBinder.Eval(Container.DataItem, "nombre") %></h2>  5.       6.     <asp:Repeater ID="RepeaterPeliculas" runat="server">  7.       <HeaderTemplate>  8.         <ul>  9.       </HeaderTemplate>  10.         11.       <ItemTemplate>  12.         <li>  13.           <%# DataBinder.Eval(Container.DataItem, "titulo") %>   14.           (<%# DataBinder.Eval(Container.DataItem, "anyo") %>)  15.         </li>  16.       </ItemTemplate>  17.         18.       <FooterTemplate>  19.         </ul>  20.       </FooterTemplate>  21.     </asp:Repeater>  

22.   </ItemTemplate>  23. </asp:repeater>  24.   25. <asp:SqlDataSource ID="SqlDataSourceGeneros" runat="server"   26.   ConnectionString="<%$ ConnectionStrings:ConnectionPeliculas %>"   27.   SelectCommand="SELECT [id], [nombre] FROM [generos]">  28. </asp:SqlDataSource>  

Lo primero que ha cambiado ha sido la sentencia del SqlDataSource, en esta ocasión seleccionamos todos los tipos de géneros que hay en nuestra base de datos. El Repeater mas externo, RepeaterGeneros, no contiene ni HeaderTemplate ni FooterTemplate, únicamente existe unItemTemplate en el cual recuperamos el nombre del género y lo mostramos. Posteriormente creamos otro Repeater, RepeaterPeliculas, dentro del ItemTemplate y en esta ocasión le ponemos como antes una cabecera, un pie y los ítems. Por último capturaremos el evento onitemdatabounddel RepeaterGeneros que se lanzará cada vez que se añada un nuevo ítem, es decir, un nuevo género. Lo que haremos en este evento es lo siguiente:

1. protected void RepeaterGeneros_ItemDataBound(object sender, RepeaterItemEventArgs e)  2. {  3.   if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)  4.   {  5.     // Recuperamos el id del genero actual  6.     string generoId = ((System.Data.DataRowView)(e.Item.DataItem)).Row["id"].ToString();  7.   8.     // Creamos la sentencia para recupera las películas del genero actual  9.     string selectCommand = "SELECT p.titulo, p.anyo FROM peliculas p INNER JOIN " +  10.       "pelicula_genero pg on (p.id = pg.pelicula_id) WHERE pg.genero_id = " + generoId;  11.   12.     // Creamos un SqlDataSource que enlazaremos al Repeater anidado  13.     SqlDataSource dataSourcePeliculas = new SqlDataSource(System.Configuration.  14.       ConfigurationManager.ConnectionStrings["ConnectionPeliculas"].ToString(),   15.       selectCommand);  16.   17.     // Ahora tenemos que encontrar el Repeater que tenemos dentro del ItemTemplate  18.     System.Web.UI.WebControls.Repeater rp = (e.Item.FindControl("RepeaterPeliculas") as   19.       System.Web.UI.WebControls.Repeater);  20.       21.     rp.DataSource = dataSourcePeliculas;  22.     rp.DataBind();  23.   }  24. }  

Lo primero es comprobar que estamos tratando un ítem normal, lo que quiere decir que ni es la cabecera, ni el pie, ni otro tipo de ítem. Simplemente un Ítem. Posteriormente obtenemos el id del genero actual, creamos un SqlDataSource y lo asociamos al RepeaterPeliculas. El resultado que obtenemos después de esto es el siguiente:

Esta bastante bien, pero aún podemos mejorarlo un poco. Si nos damos cuenta el género Terror no contiene ninguna película y supongamos que en el resultado, no queremos que me salgan géneros que no contienen películas. Para ello modificaríamos el evento onitemdatabound y lo dejaríamos de la siguiente forma:

1. protected void RepeaterGeneros_ItemDataBound(object sender, RepeaterItemEventArgs e)  2. {  3.   if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)  4.   {  5.     // Recuperamos el id del genero actual  6.     string generoId = ((System.Data.DataRowView)(e.Item.DataItem)).Row["id"].ToString();  7.   8.     // Creamos la sentencia para recupera las películas del genero actual  9.     string selectCommand = "SELECT p.titulo, p.anyo FROM peliculas p INNER JOIN " +  10.       "pelicula_genero pg on (p.id = pg.pelicula_id) WHERE pg.genero_id = " + generoId;  11.   12.     // Creamos un SqlDataSource que enlazaremos al Repeater anidado  13.     SqlDataSource dataSourcePeliculas = new SqlDataSource(System.Configuration.  14.       ConfigurationManager.ConnectionStrings["ConnectionPeliculas"].ToString(),   15.       selectCommand);  16.   17.     // Ahora tenemos que encontrar el Repeater que tenemos dentro del ItemTemplate  18.     System.Web.UI.WebControls.Repeater rp = (e.Item.FindControl("RepeaterPeliculas") as   19.       System.Web.UI.WebControls.Repeater);  20.       21.     rp.DataSource = dataSourcePeliculas;  

22.     rp.DataBind();  23.   24.     // Comprobamos si hay películas  25.     if (rp.Items.Count == 0)  26.       e.Item.Visible = false;  27.   }  28. }  

Hemos añadido una condición al final que comprueba si existen películas de ese género, en caso de no existir oculta el género y no se visualiza en el resultado final.

Aquí termina esta entrada sobre el control Repeater de ASP.NET, espero que aunque sea un ejemplo muy sencillo pueda resultar de utilidad.

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.

3. </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.Ejemplo de Fieldset con Legend

<style type="text/css"> fieldset.elist, input[type="text"], textarea, select, option, fieldset.elist ul, fieldset.elist > legend, fieldset.elist input[type="text"], fieldset.elist > legend:after { -webkit-box-sizing: border-box; -moz-box-sizing: border-box; box-sizing: border-box;}

input[type="text"] { padding: 0 20px;}

textarea { width: 500px; height: 200px; padding: 20px;}

textarea, input[type="text"], fieldset.elist ul, select, fieldset.elist > legend { border: 2px #cccccc solid; border-radius: 10px;}

input[type="text"], fieldset.elist, select, fieldset.elist > legend { height: 32px; font-family: Tahoma; font-size: 14px;}

input[type="text"]:hover, textarea:hover, select:hover, fieldset.elist:hover > legend { background-color: #ddddff;}

select { padding: 4px 20px;}

option { height: 30px; padding: 5px 4px;

}

option:not(:checked), textarea:focus { background-color: #ffcccc;}

fieldset.elist > legend:after, fieldset.elist label { height: 28px;}

input[type="text"], fieldset.elist { width: 316px;}

input[type="text"]:focus { background: #ffcccc url("data:image/gif;base64,R0lGODlhEAAQANU5APnoxuvr6+uxPdvb2+rq6ri4uO7qxunp6dPT06SHV+/rx8vLy+nezLO0sbe3t9Ksas+qaaCEV8rKyp2dnf39/QAAAK6ursifZHFxcc/Qzu3mxYyMjExCJnV1dc6maO7u7o+Pj2tXNoaGhtfDpKCDVu3lxM+tcaKEV9bW1qOFVWNjY8KrisTExNra2nBbObGxsby8vO/mu7Kyso9ZAuzs7MSgAIiKhf///8zMzP///wAAAAAAAAAAAAAAAAAAAAAAACH5BAEAADkALAAAAAAQABAAAAaXwJxwSCwOYzWkMpkkZmoAqDQaJdpqAqw2m53NRjlboAarFczomcE0C99o8DgNMVM8Tm3bbYDr9x11DwkzDG5yc2oQJIRCenx/MxoeETM2Q3pxATMlF4MYlo17OAsdLispMyAioIY0BzMcITMTKBasjgssFTMqGxItMjYUoTQBBAQHxgE0wZcfMtDRMi/QrA022NnaNg1CQQA7") no-repeat 2px center !important;}

input[type="text"]:focus, textarea:focus, select:focus, fieldset.elist > legend { border: 2px #ccaaaa solid;}

fieldset { border: 2px #af3333 solid; border-radius: 10px;}

/* Editable [pseudo]select (i.e. fieldsets with [class=elist]) */

fieldset.elist { display: inline-block; position: relative; vertical-align: middle; overflow: visible; padding: 0; margin: 0; border: none;}

fieldset.elist ul { position: absolute; width: 100%; max-height: 320px; padding: 0; margin: 0; overflow: hidden; background-color: transparent;}

fieldset.elist:hover ul { background-color: #ffffff; border: 2px #af3333 solid; left: 2px; overflow: auto;}

fieldset.elist ul > li { list-style-type: none; background-color: transparent;}

fieldset.elist label { display: none; width: 100%;}

fieldset.elist input[type="text"] { width: 100%; height: 30px; line-height: 30px; border: none; background-color: transparent; border-radius: 0;}

fieldset.elist > legend { display: block; margin: 0; padding: 0 0 0 5px; position: absolute; width: 100%; cursor: default; background-color: #ccffcc; line-height: 30px; font-style: italic;}

fieldset.elist:hover > legend { position: relative; overflow: hidden;}

fieldset.elist > legend:after { width: 20px; content: "\2335"; float: right; text-align: center; border-left: 2px #cccccc solid; font-style: normal; cursor: default;}

fieldset.elist:hover > legend:after { background-color: #99ff99;}

fieldset.elist ul input[type="radio"] { display: none;}

fieldset.elist input[type="radio"]:checked ~ label { display: block; width: 292px; background-color: #ffffff;}

fieldset.elist:hover input[type="radio"]:checked ~ label { width: 100%;}

fieldset.elist:hover label { display: block; height: 100%;}

fieldset.elist label:hover { background-color: #3333ff !important;}

fieldset.elist:hover input[type="radio"]:checked ~ label { background-color: #aaaaaa;} </style>///////////////////<fieldset> <legend>Order a T-Shirt</legend> <p>Write your name (simple textbox): <input type="text" name="myname" /></p> <p>Choose your size (simple select): <select name="size"> <option value="s">Small</option> <option value="m">Medium</option> <option value="l">Large</option> <option value="xl">Extra Large</option> </select></p> <div>What address do you want to use? (editabile pseudoselect) <fieldset class="elist"> <legend>Address&hellip;</legend> <ul> <li><input type="radio" name="address-chosen" value="1" id="address-switch_1" checked /><label for="address-switch_1"><input type="text" name="address-item_1" value="19 Quaker Ridge Rd. Bethel CT 06801" /></label></li> <li><input type="radio" name="address-chosen" value="2" id="address-switch_2" /><label for="address-switch_2"><input type="text" name="address-item_2" value="1000 Coney Island Ave. Brooklyn NY 11230" /></label></li> <li><input type="radio" name="address-chosen" value="3" id="address-switch_3" /><label for="address-switch_3"><input type="text" name="address-item_3" value="2962 Dunedin Cv. Germantown TN 38138" /></label></li> <li><input type="radio" name="address-chosen" value="4" id="address-switch_4" /><label for="address-switch_4"><input type="text" name="address-item_4" value="915 E 7th St. Apt 6L. Brooklyn NY 11230" /></label></li> </ul> </fieldset> </div> <p>Write a comment:<br /> <textarea name="comment"></textarea></p> <p><input type="reset" value="Reset" /> <input type="submit" value="Send!" /></p></fieldset>

//////////////////

Salida

https://developer.mozilla.org/en-US/docs/Web/HTML/Element/fieldset

Los procedimientos almacenados de SQL Server son una gran herramienta para poder hacer parte de nuestro trabajo de acceso a datos dentro del propio servidor.Pero cuando empezamos a crear procedimientos almacenados cada vez más y más complicados llega un momento en el que nos encontramos con la necesidad de que nuestro procedimiento reciba un número indeterminado de parámetros.Cuando esto me ocurrió a mi recuerdo que me puse a buscar en los BOL como podía pasar un Array a mi procedimiento, pero me encontré con la imposibilidad de trabajar con Arrays en TSQL.Así que buscando un poco más encontré un par de métodos para hacer el trabajo "a mano" y eso es lo que vamos a comentar aquí.Solución 1. Paso de un stringUna primera solución es pasar un string al procedimiento almacenado donde incluimos todos losparámetros. Dentro del procedimiento almacenado partimos nuestro string en los parámetros que lo componen y podemos trabajar con ellos.Veamos un ejemplo en el que una serie de valores se pasan al procedimiento almacenado separados por comas y dentro del procedimiento separamos la cadena en sus parámetros constituyentes.Vamos a pasar el string "valor1,valor2,valor3" para que el procedimiento almacenado lo descomponga en "valor1", "valor2", "valor3".El procedimiento almacenado será el siguiente:CREATE PROCEDURE RecibirParametros @Parametros varchar(1000)--@Parametros es la cadena de entradaAS--Creamos una tabla temporal por simplificar el trabajo--y almacenar los parametros que vayamos obteniendoCREATE TABLE #parametros (parametro varchar(1000))SET NOCOUNT ON--El separador de nuestros parametros sera una ,DECLARE @Posicion int--@Posicion es la posicion de cada uno de nuestros separadoresDECLARE @Parametro varchar(1000)--@Parametro es cada uno de los valores obtenidos--que almacenaremos en #parametrosSET @Parametros = @Parametros + ','--Colocamos un separador al final de los parametros--para que funcione bien nuestro codigo--Hacemos un bucle que se repite mientras haya separadoresWHILE patindex('%,%' , @Parametros) <> 0--patindex busca un patron en una cadena y nos devuelve su posicionBEGIN SELECT @Posicion = patindex('%,%' , @Parametros) --Buscamos la posicion de la primera , SELECT @Parametro = left(@Parametros, @Posicion - 1) --Y cogemos los caracteres hasta esa posicion INSERT INTO #parametros values (@Parametro) --y ese parámetro lo guardamos en la tabla temporal --Reemplazamos lo procesado con nada con la funcion stuff SELECT @Parametros = stuff(@Parametros, 1, @Posicion, '')END--Y cuando se han recorrido todos los parametros sacamos por pantalla el resultadoSELECT * FROM #parametrosSET NOCOUNT OFFGOPara probar como funcionaEXECUTE RecibirParametros 'valor1,valor2,valor3'parametro--------------valor1

valor2valor3por supuesto que habitualmente no querremos separar la cadena de entrada en parámetros sin más, sino que queremos tratarlos de alguna manera. Pero el funcionamiento esencial es el mismo que el aquí presentado.Solución 2. Separación por XMLComo el formato XML cada vez está más de moda para transmitir información se nos puede ocurrir que los parámetros a pasar al procedimiento almacenado podrían tener ese formato,sobre todo sabiendo que el SQL Server tiene unas cuantas funciones sencillas y potentes para trabajar con datos descritos en este lenguaje.Pues vamos a ello. En esta segunda solución la colección de parámetros vamos a pasarla como una cadena pero formateada con XML. Podemos dar el siguiente aspecto a nuestros parámetros.<raiz><parametro valor="valor1"/><parametro valor="valor2"/><parametro valor="valor2"/></raiz>Y los parámetros descritos con este formato serán nuestra cadena de entrada'<raiz><parametro valor="Valor1"/><parametro valor="Valor2"/>

<parametro valor="Valor2"/></raiz>'El procedimiento almacenado que leerá esta cadena y nos devolverá los parámetros en una tabla (para que sea similar al anterior) es el siguiente:CREATE PROCEDURE RecibirParametrosXML @Parametros varchar(1000)--@Parametros es la cadena XML de entradaASCREATE TABLE #Parametros (Parametro varchar(1000))--Creamos la tabla temporal para almacenar los parámetros de salidaDECLARE @idoc INT--Nos hace falta una variable de tipo int para referirnos al documento--XML con el que vamos a trabajarSET NOCOUNT ON--Preparamos el documento con sp_xmlpreparedocument--Podéis ver la descripcion de como funciona en los BOLEXEC sp_xml_preparedocument @idoc OUTPUT, @Parametro--Metemos los valores en una tabla temporal leyendolos--del documento que hemos preparado. Para ello usamos el comando--OpenXml. Podéis ver también como funciona en los BOLINSERT INTO #Parametros Select * FROM

OpenXml(@idoc,'raiz/parametro',1) with (valor Varchar(1000))--Mostramos el resultadoSELECT * FROM #Parametros--y liberamos la memoria ocupadaexec sp_xml_removedocument @idoc outputY por supuesto para probarloEXECUTE recibirparametrosXML '<principal><parametro valor="Valor1"/>

<parametro valor="Valor2"/><parametro valor="Valor2"/></principal>'Parametro------------------Valor1Valor2Valor2El resultado es el mismo que antes.Como podemos ver la imposibilidad de pasar Arrays no es un límite si utilizamos un poco de imaginación. Ahora podemos escoger si queremos usar un método más clásico y pasar los parámetros en una cadena o nos podemos decantar por una tecnología más en boga y utilizar (de alguna manera) el lenguaje XML para pasar información a nuestro procedimiento almacenado.http://www.programacion.com/articulo/arrays_de_parametros_en_procedimientos_almacenados_en_sql_server_259