Compartir a través de


Agregar una columna GridView de botones de radio (C#)

de Scott Mitchell

Descargar PDF

En este tutorial se examina cómo agregar una columna de botones de radio a un control GridView para proporcionar al usuario una manera más intuitiva de seleccionar una sola fila de GridView.

Introducción

El control GridView ofrece una gran cantidad de funcionalidad integrada. Incluye varios campos diferentes para mostrar texto, imágenes, hipervínculos y botones. Admite plantillas para una mayor personalización. Con unos pocos clics del ratón, es posible crear un GridView donde cada fila se pueda seleccionar mediante un botón, o habilitar opciones de edición o eliminación. A pesar de la gran cantidad de características proporcionadas, a menudo habrá situaciones en las que se deberán agregar características adicionales no admitidas. En este tutorial y los dos siguientes examinaremos cómo mejorar la funcionalidad de GridView para incluir características adicionales.

Este tutorial y el siguiente se centran en mejorar el proceso de selección de filas. Como se examina en el Master/Detail Using a Selectable Master GridView with a Details DetailView, podemos agregar un CommandField al GridView que incluye un botón de selección. Cuando se hace clic, se produce una devolución de datos y la propiedad de SelectedIndex de GridView se actualiza al índice de la fila cuyo botón Seleccionar fue presionado. En el tutorial Master/Detail Using a Selectable Master GridView with a Details DetailView, vimos cómo usar esta función para mostrar los detalles de la fila GridView seleccionada.

Aunque el botón Seleccionar funciona en muchas situaciones, puede que no funcione también para otros. En lugar de usar un botón, se suelen usar otros dos elementos de interfaz de usuario para la selección: el botón de radio y la casilla. Podemos aumentar GridView para que, en lugar de un botón Seleccionar, cada fila contenga un botón de radio o una casilla. En escenarios en los que el usuario solo puede seleccionar uno de los registros GridView, es posible que se prefiera el botón de radio sobre el botón Seleccionar. En situaciones en las que el usuario tiene la posibilidad de seleccionar varios registros, como en una aplicación de correo electrónico basada en web, donde podría querer seleccionar múltiples mensajes para eliminar, la casilla de verificación ofrece una funcionalidad que no está disponible en las interfaces de usuario del botón de selección o del botón de opción.

En este tutorial se explica cómo agregar una columna de botones de radio a GridView. En el tutorial siguiente se explora el uso de casillas.

Paso 1: Crear y mejorar las páginas web de GridView

Antes de empezar a mejorar GridView para incluir una columna de botones de radio, primero tomemos un momento para crear las páginas de ASP.NET en nuestro proyecto de sitio web que necesitaremos para este tutorial y los dos siguientes. Para empezar, agregue una nueva carpeta denominada EnhancedGridView. Después, agregue las siguientes páginas ASP.NET a esa carpeta, asegurándose de asociar cada página a la página maestra Site.master:

  • Default.aspx
  • RadioButtonField.aspx
  • CheckBoxField.aspx
  • InsertThroughFooter.aspx

Agregar las páginas de ASP.NET para los tutoriales de SqlDataSource-Related

Figura 1: Adición de las páginas ASP.NET para los tutoriales relacionados con el control SqlDataSource

Igual que en las otras carpetas, Default.aspx en la carpeta EnhancedGridView enumerará los tutoriales en su sección. Recuerde que el control de usuario SectionLevelTutorialListing.ascx proporciona esta funcionalidad. Por lo tanto, agregue este control de usuario a Default.aspx arrastrándolo desde el Explorador de soluciones a la vista Diseño de la página.

Agregue el control de usuario SectionLevelTutorialListing.ascx a Default.aspx

Figura 2: Agregar el control de usuario a SectionLevelTutorialListing.ascx (Default.aspx la imagen de tamaño completo)

Por último, agregue las siguientes cuatro páginas como entradas al archivo Web.sitemap. En concreto, agregue el siguiente marcado después de usar el Control de origen de datos SQL <siteMapNode>:

<siteMapNode 
    title="Enhancing the GridView" 
    url="~/EnhancedGridView/Default.aspx" 
    description="Augment the user experience of the GridView control.">
    <siteMapNode 
        url="~/EnhancedGridView/RadioButtonField.aspx" 
        title="Selection via a Radio Button Column" 
        description="Explore how to add a column of radio buttons in the GridView." />
    <siteMapNode 
        url="~/EnhancedGridView/CheckBoxField.aspx" 
        title="Selection via a Checkbox Column" 
        description="Select multiple records in the GridView by using a column of 
            checkboxes." />
    <siteMapNode 
        url="~/EnhancedGridView/InsertThroughFooter.aspx" 
        title="Add New Records through the Footer" 
        description="Learn how to allow users to add new records through the 
            GridView's footer." />
</siteMapNode>

Después de actualizar Web.sitemap, dedique un momento a ver el sitio web de los tutoriales desde un explorador. Ahora el menú de la izquierda incluye elementos para los tutoriales sobre edición, inserción y eliminación.

El mapa del sitio ahora incluye entradas para mejorar los tutoriales de GridView

Figura 3: El mapa del sitio ahora incluye entradas para mejorar los tutoriales de GridView

Paso 2: Mostrar los proveedores en un control GridView

Para este tutorial, vamos a crear un GridView que enumera a los proveedores de los Estados Unidos, con cada fila del GridView proporcionando un botón de radio. Después de seleccionar un proveedor a través del botón de radio, el usuario puede ver los productos del proveedor haciendo clic en un botón. Aunque esta tarea puede sonar trivial, hay una serie de sutilezas que lo hacen particularmente complicado. Antes de profundizar en estas sutilezas, primero vamos a obtener un GridView que enumera los proveedores.

Para empezar, abra la página RadioButtonField.aspx en la carpeta EnhancedGridView y, a continuación, arrastre un GridView desde el Toolbox al Diseñador. Establezca el ID de GridView en Suppliers y, desde su etiqueta inteligente, elija crear un nuevo origen de datos. En concreto, cree un ObjectDataSource denominado SuppliersDataSource que extraiga sus datos del SuppliersBLL objeto .

Crear un nuevo ObjectDataSource denominado SuppliersDataSource

Figura 4: Crear un nuevo objetoDataSource denominado SuppliersDataSource (haga clic para ver la imagen de tamaño completo)

Captura de pantalla de la ventana Configurar origen de datos - ProveedoresDataSource con el objeto de negocio ProveedoresBLL seleccionado y el botón Siguiente resaltado.

Figura 5: Configuración de ObjectDataSource para usar la clase SuppliersBLL (Haga clic para ver la imagen a tamaño completo)

Puesto que solo queremos enumerar esos proveedores en Estados Unidos, elija el GetSuppliersByCountry(country) método en la lista desplegable de la pestaña SELECT.

Captura de pantalla de la ventana Configurar origen de datos - ProveedoresDataSource con la pestaña SELECT abierta. La opción de método GetSupplierByCountry está seleccionada y el botón Siguiente está resaltado.

Figura 6: Configurar objectDataSource para usar la clase (SuppliersBLL imagen de tamaño completo)

En la pestaña UPDATE , seleccione la opción (Ninguno) y haga clic en Siguiente.

Captura de pantalla de la ventana Configurar origen de datos - ProveedoresDataSource con la pestaña UPDATE abierta. La opción de método (Ninguno) está seleccionada y el botón Siguiente está resaltado.

Figura 7: Configurar objectDataSource para usar la clase (SuppliersBLL imagen de tamaño completo)

Dado que el GetSuppliersByCountry(country) método acepta un parámetro, el Asistente para configurar orígenes de datos nos pide el origen de ese parámetro. Para especificar un valor codificado de forma rígida ( USA, en este ejemplo), deje la lista desplegable Origen de parámetros establecida en Ninguno y escriba el valor predeterminado en el cuadro de texto. Haga clic en Finalizar para completar el asistente.

Usar EE. UU. como valor predeterminado para el parámetro country

Figura 8: Usar EE. UU. como valor predeterminado para el parámetro (country imagen de tamaño completo)

Después de completar el asistente, GridView incluirá un BoundField para cada uno de los campos de datos del proveedor. Quite todos los BoundFields excepto CompanyName, City y Country, y cambie el nombre de la propiedad BoundFields CompanyNameHeaderText a Proveedor. Después de hacerlo, la sintaxis declarativa GridView y ObjectDataSource debe ser similar a la siguiente.

<asp:GridView ID="Suppliers" runat="server" AutoGenerateColumns="False"
    DataKeyNames="SupplierID" DataSourceID="SuppliersDataSource" 
    EnableViewState="False">
    <Columns>
        <asp:BoundField DataField="CompanyName" HeaderText="Supplier" 
            SortExpression="CompanyName" />
        <asp:BoundField DataField="City" HeaderText="City" 
            SortExpression="City" />
        <asp:BoundField DataField="Country" HeaderText="Country" 
            SortExpression="Country" />
    </Columns>
</asp:GridView>
<asp:ObjectDataSource ID="SuppliersDataSource" runat="server" 
    OldValuesParameterFormatString="original_{0}"
    SelectMethod="GetSuppliersByCountry" TypeName="SuppliersBLL">
    <SelectParameters>
        <asp:Parameter DefaultValue="USA" Name="country" Type="String" />
    </SelectParameters>
</asp:ObjectDataSource>

En este tutorial, vamos a permitir que el usuario vea los productos del proveedor seleccionado en la misma página que la lista de proveedores o en otra página. Para acomodar esto, agregue dos controles web de botón a la página. He configurado los ID de estos dos Botones a ListProducts y SendToProducts, con la idea de que cuando se haga clic en ListProducts, se producirá un postback y los productos del proveedor seleccionado aparecerán en la misma página, pero cuando se haga clic en SendToProducts, el usuario será llevado a otra página que enumera los productos.

En la figura 9 se muestran el Suppliers GridView y los dos controles web de botón cuando se ven a través de un navegador.

Esos proveedores de Estados Unidos tienen su nombre, ciudad e información de país en la lista

Figura 9: Esos proveedores de ESTADOS Unidos tienen su nombre, ciudad e información de país enumerados (haga clic para ver la imagen de tamaño completo)

Paso 3: Agregar una columna de botones de radio

En este momento, Suppliers GridView tiene tres BoundFields que muestran el nombre de la compañía, la ciudad y el país de cada proveedor en estados Unidos. Sin embargo, todavía falta una columna de botones de radio. Desafortunadamente, GridView no incluye un RadioButtonField integrado por defecto; de lo contrario, podríamos agregarlo a la cuadrícula y sería suficiente. En su lugar, podemos agregar un TemplateField y configurar su ItemTemplate para representar un botón de radio, lo que da como resultado un botón de radio para cada fila gridView.

Inicialmente, podríamos suponer que la interfaz de usuario deseada se puede implementar agregando un control Web RadioButton al ItemTemplate de un TemplateField. Aunque esto agregará realmente un solo botón de radio a cada fila de GridView, los botones de radio no se pueden agrupar y, por lo tanto, no son mutuamente excluyentes. Es decir, un usuario final puede seleccionar varios botones de radio simultáneamente desde GridView.

Aunque usar un TemplateField de controles Web tipo RadioButton no proporciona la funcionalidad que necesitamos, vamos a seguir este enfoque, ya que es valioso analizar por qué los botones de radio resultantes no están agrupados. Empiece agregando un TemplateField al GridView de Proveedores, convirtiéndolo en el campo más a la izquierda. A continuación, desde la etiqueta inteligente GridView, haga clic en el vínculo Editar plantillas y arrastre un control Web RadioButton desde el Cuadro de herramientas a los campos ItemTemplate de plantilla (vea la figura 10). Establezca la propiedad del RadioButton en ID a RowSelector y la propiedad GroupName a SuppliersGroup.

Agregar un control web de tipo RadioButton al ItemTemplate

Figura 10: Agregar un control web RadioButton a ItemTemplate (Haga clic para ver la imagen de tamaño completo)

Después de realizar estas adiciones a través del Diseñador, el marcado de GridView debe ser similar al siguiente:

<asp:GridView ID="Suppliers" runat="server" AutoGenerateColumns="False"
    DataKeyNames="SupplierID" DataSourceID="SuppliersDataSource" 
    EnableViewState="False">
    <Columns>
        <asp:TemplateField>
            <ItemTemplate>
                <asp:RadioButton ID="RowSelector" runat="server" 
                    GroupName="SuppliersGroup" />
            </ItemTemplate>
        </asp:TemplateField>
        <asp:BoundField DataField="CompanyName" HeaderText="Supplier" 
            SortExpression="CompanyName" />
        <asp:BoundField DataField="City" HeaderText="City" 
            SortExpression="City" />
        <asp:BoundField DataField="Country" HeaderText="Country" 
            SortExpression="Country" />
    </Columns>
</asp:GridView>

La propiedad RadioButton GroupName es lo que se usa para agrupar una serie de botones de radio. Todos los controles RadioButton con el mismo GroupName valor se consideran agrupados; solo se puede seleccionar un botón de radio de un grupo a la vez. La GroupName propiedad especifica el valor del atributo del name botón de radio representado. El explorador examina los atributos de los botones name de radio para determinar las agrupaciones de botones de radio.

Con el control web RadioButton agregado a ItemTemplate, visite esta página mediante un navegador y haga clic en los botones de radio de las filas de la cuadrícula. Observe cómo no se agrupan los botones de radio, lo que permite seleccionar todas las filas, como se muestra en la figura 11.

Los botones de radio de GridView no están agrupados

Figura 11: Los botones de radio de GridView no están agrupados (haga clic para ver la imagen de tamaño completo)

La razón por la que los botones de radio no están agrupados es porque sus atributos representados name son diferentes, a pesar de tener la misma GroupName configuración de propiedad. Para ver estas diferencias, haga clic en Ver/Código fuente desde el navegador y examine el marcado del botón de radio.

<input id="ctl00_MainContent_Suppliers_ctl02_RowSelector" 
    name="ctl00$MainContent$Suppliers$ctl02$SuppliersGroup" 
    type="radio" value="RowSelector" />
<input id="ctl00_MainContent_Suppliers_ctl03_RowSelector" 
    name="ctl00$MainContent$Suppliers$ctl03$SuppliersGroup" 
    type="radio" value="RowSelector" />
<input id="ctl00_MainContent_Suppliers_ctl04_RowSelector" 
    name="ctl00$MainContent$Suppliers$ctl04$SuppliersGroup" 
    type="radio" value="RowSelector" />
<input id="ctl00_MainContent_Suppliers_ctl05_RowSelector" 
    name="ctl00$MainContent$Suppliers$ctl05$SuppliersGroup" 
    type="radio" value="RowSelector" />

Observe cómo los atributos name y id no son los valores exactos, como se especifica en la ventana de Propiedades, sino que están precedidos por una serie de otros valores ID. Los valores adicionales ID agregados al inicio de los atributos generados id y name son los ID de los controles principales de los botones de radio, los GridViewRowID, el GridView ID, el control de contenido ID y los formularios web ID. Estos ID se agregan para que cada control web representado en GridView tenga un valor único id y name .

Cada control representado necesita un control diferente name y id , dado que este es el modo en que el explorador identifica de forma única cada control en el lado cliente y cómo identifica al servidor web qué acción o cambio se ha producido en postback. Por ejemplo, imagine que queríamos ejecutar código del lado servidor cada vez que se cambiaba el estado comprobado de RadioButton. Podríamos lograr esto estableciendo la propiedad AutoPostBack de RadioButton en true y creando un controlador para el evento CheckChanged. Sin embargo, si los valores representados name y id para todos los botones de radio eran los mismos, en postback no pudimos determinar qué radioButton específico se hizo clic.

El resumen es que no podemos crear una columna de botones de radio en gridView mediante el control Web RadioButton. En su lugar, debemos usar técnicas bastante arcaicas para garantizar que el marcado adecuado se inserte en cada fila gridView.

Nota:

Al igual que el control Web RadioButton, el control HTML del botón de radio, cuando se agrega a una plantilla, incluirá el atributo único name , lo que hará que los botones de radio de la cuadrícula no se agrupen. Si no está familiarizado con los controles HTML, no dude en ignorar esta nota, ya que los controles HTML rara vez se usan, especialmente en ASP.NET 2.0. Pero si está interesado en aprender más, consulte la entrada de blog de K. Scott Allen controles web y controles HTML.

Usar un control literal para insertar marcado de botón de radio

Para agrupar correctamente todos los botones de radio dentro de GridView, es necesario insertar manualmente el marcado de los botones de radio en .ItemTemplate Cada botón de radio necesita el mismo name atributo, pero debe tener un atributo único id (en caso de que deseemos acceder a un botón de radio a través del script del lado cliente). Después de que un usuario seleccione un botón de radio y publique la página, el explorador devolverá el valor del atributo del value botón de radio seleccionado. Por lo tanto, cada botón de radio necesitará un atributo único value . Por último, en postback, debemos asegurarnos de agregar el checked atributo al botón de radio seleccionado; de lo contrario, después de que el usuario realice una selección y vuelva a publicar, los botones de radio volverán a su estado predeterminado (todos no seleccionados).

Hay dos enfoques que se pueden adoptar para insertar marcado de bajo nivel en una plantilla. Una consiste en realizar una combinación de marcado y llamadas a métodos de formato definidos en la clase de código subyacente. Esta técnica se explicó por primera vez en el tutorial Uso de TemplateFields en el control GridView . En nuestro caso podría tener un aspecto similar al siguiente:

<input type="radio" id='<%# GetUniqueRadioButtonID(...) %>' 
    name='SuppliersGroup' value='<%# GetRadioButtonValue(...) %>' ... />

Aquí, GetUniqueRadioButton y GetRadioButtonValue serían métodos definidos en la clase de código subyacente que devolverían los valores de atributo id y value adecuados para cada botón de radio. Este enfoque funciona bien para asignar los id atributos y value , pero se queda corto cuando se necesita especificar el valor del checked atributo porque la sintaxis de enlace de datos solo se ejecuta cuando los datos se enlazan por primera vez a GridView. Por lo tanto, si GridView tiene el estado de vista habilitado, los métodos de formato solo se activarán cuando la página se cargue por primera vez (o cuando GridView vuelva explícitamente al origen de datos) y, por tanto, la función que establece el checked atributo no se llamará en postback. Es un problema bastante sutil y un poco más allá del ámbito de este artículo, así que lo dejaré en esto. Sin embargo, yo le animo a intentar usar el enfoque mencionado anteriormente y desarrollarlo hasta el punto en donde podrías quedarte atascado. Aunque este ejercicio no le acercará a una versión de trabajo, le ayudará a fomentar una comprensión más profunda de GridView y el ciclo de vida de enlace de datos.

El otro enfoque para insertar marcado personalizado y de bajo nivel en una plantilla y el enfoque que usaremos para este tutorial es agregar un control Literal a la plantilla. A continuación, en el controlador de eventos del RowCreated o RowDataBound de GridView, se puede acceder al control Literal mediante programación y se establece su propiedad Text con el marcado que se va a emitir.

Para empezar, quite el control RadioButton de TemplateField s ItemTemplate, reemplazandolo por un control Literal. Establezca el control Literal en IDRadioButtonMarkup.

Agregar un control literal al ItemTemplate

Figura 12: Agregar un control literal a ItemTemplate (haga clic para ver la imagen de tamaño completo)

A continuación, cree un controlador de eventos para el evento GridView s RowCreated . El RowCreated evento se desencadena una vez por cada fila agregada, independientemente de si los datos se están volviendo a la clase GridView o no. Esto significa que incluso en un postback cuando los datos se vuelven a cargar desde el view state, el evento RowCreated se dispara y este es el motivo por el que lo estamos usando en lugar de RowDataBound (que se dispara solo cuando los datos se enlazan explícitamente al control web de datos).

En este controlador de eventos, solo queremos continuar si estamos tratando con una fila de datos. Para cada fila de datos, queremos referenciar programáticamente el control RadioButtonMarkup Literal y establecer su propiedad Text al marcado que se va a emitir. Como muestra el siguiente código, el marcado emitido crea un botón de radio cuyo name atributo se establece en SuppliersGroup, cuyo id atributo se establece en RowSelectorX, donde X es el índice de la fila de GridView, y cuyo value atributo se establece en el índice de la fila de GridView.

protected void Suppliers_RowCreated(object sender, GridViewRowEventArgs e)
{
    if (e.Row.RowType == DataControlRowType.DataRow)
    {
        // Grab a reference to the Literal control
        Literal output = (Literal)e.Row.FindControl("RadioButtonMarkup");
        // Output the markup except for the "checked" attribute
        output.Text = string.Format(
            @"<input type="radio" name="SuppliersGroup" " +
            @"id="RowSelector{0}" value="{0}" />", e.Row.RowIndex);
    }
}

Cuando se selecciona una fila de GridView y se produce un postback, nos interesa el SupplierID del proveedor seleccionado. Por lo tanto, podría pensarse que el valor de cada botón de radio debe ser el real SupplierID (en lugar del índice de la fila GridView). Aunque esto puede funcionar en determinadas circunstancias, sería un riesgo de seguridad aceptar y procesar ciegamente un SupplierID. Nuestro GridView, por ejemplo, enumera solo los proveedores de Estados Unidos. Sin embargo, si SupplierID se pasa directamente desde el botón de radio, ¿qué impide que un usuario malintencionado manipule el valor que se envía de vuelta en el postback? Mediante el uso del índice de fila como value y, a continuación, obtener el SupplierID en el postback de la colección DataKeys, podemos asegurarnos de que el usuario solo usa uno de los SupplierID valores asociados a una de las filas de la GridView.

Después de agregar este código de controlador de eventos, dedique un minuto a probar la página en un explorador. En primer lugar, tenga en cuenta que solo se puede seleccionar un botón de radio en la cuadrícula a la vez. Sin embargo, al seleccionar un botón de radio y hacer clic en uno de los botones, se produce un postback y los botones de radio vuelven a su estado inicial (es decir, en postback, el botón de radio seleccionado ya no está seleccionado). Para corregir esto, es necesario aumentar el RowCreated controlador de eventos para que inspeccione el índice de botón de radio seleccionado enviado desde la devolución y agregue el checked="checked" atributo al marcado emitido de las coincidencias del índice de fila.

Cuando se produce un postback, el explorador devuelve el name y el value del botón de opción seleccionado. El valor se puede recuperar mediante programación mediante Request.Form["name"]. La Request.Form propiedad proporciona una NameValueCollection representación de las variables de formulario. Las variables del formulario son los nombres y los valores de los campos de la página web, y el explorador web las envía cada vez que se produce una devolución de entrada. Dado que el atributo representado name de los botones de radio en el GridView es SuppliersGroup, cuando se envía de nuevo la página web, el navegador enviará SuppliersGroup=valueOfSelectedRadioButton al servidor web (junto con los demás campos del formulario). A continuación, se puede acceder a esta información desde la Request.Form propiedad mediante: Request.Form["SuppliersGroup"].

Puesto que tendremos que determinar el índice de botón de radio seleccionado no solo en el RowCreated controlador de eventos, sino en los Click controladores de eventos para los controles Web Button, vamos a agregar una SuppliersSelectedIndex propiedad a la clase de código subyacente que devuelve -1 si no se seleccionó ningún botón de radio y el índice seleccionado si se selecciona uno de los botones de radio.

private int SuppliersSelectedIndex
{
    get
    {
        if (string.IsNullOrEmpty(Request.Form["SuppliersGroup"]))
            return -1;
        else
            return Convert.ToInt32(Request.Form["SuppliersGroup"]);
    }
}

Con esta propiedad agregada, sabemos agregar el checked="checked" marcado en el RowCreated controlador de eventos cuando SuppliersSelectedIndex es igual a e.Row.RowIndex. Actualice el controlador de eventos para incluir esta lógica:

protected void Suppliers_RowCreated(object sender, GridViewRowEventArgs e)
{
    if (e.Row.RowType == DataControlRowType.DataRow)
    {
        // Grab a reference to the Literal control
        Literal output = (Literal)e.Row.FindControl("RadioButtonMarkup");
        // Output the markup except for the "checked" attribute
        output.Text = string.Format(
            @"<input type="radio" name="SuppliersGroup" " +
            @"id="RowSelector{0}" value="{0}"", e.Row.RowIndex);
        // See if we need to add the "checked" attribute
        if (SuppliersSelectedIndex == e.Row.RowIndex)
            output.Text += @" checked="checked"";
        // Add the closing tag
        output.Text += " />";
    }
}

Con este cambio, el botón de radio seleccionado permanece seleccionado después de un postback. Ahora que tenemos la capacidad de especificar qué botón de radio está seleccionado, podríamos cambiar el comportamiento para que cuando se visitó la página por primera vez, se seleccionó el primer botón de radio de la fila GridView (en lugar de tener ningún botón de radio seleccionado de forma predeterminada, que es el comportamiento actual). Para que el primer botón de radio esté seleccionado de forma predeterminada, simplemente cambie la if (SuppliersSelectedIndex == e.Row.RowIndex) declaración a lo siguiente: if (SuppliersSelectedIndex == e.Row.RowIndex || (!Page.IsPostBack && e.Row.RowIndex == 0)).

En este momento hemos agregado una columna de botones de radio agrupados a la GridView que permite seleccionar una sola fila de la GridView y recordar la selección a través de los postbacks. Nuestros pasos siguientes son mostrar los productos proporcionados por el proveedor seleccionado. En el paso 4 veremos cómo redirigir al usuario a otra página, enviando la selección SupplierID. En el paso 5, veremos cómo mostrar los productos del proveedor seleccionado en gridView en la misma página.

Nota:

En lugar de usar templateField (el foco de este largo paso 3), podríamos crear una clase personalizada DataControlField que represente la interfaz de usuario y la funcionalidad adecuadas. La DataControlField clase es la clase base de la que derivan los campos BoundField, CheckBoxField, TemplateField y otros campos GridView y DetailsView integrados. La creación de una clase personalizada DataControlField significaría que la columna de botones de radio podría agregarse simplemente mediante sintaxis declarativa, y también haría que la replicación de la funcionalidad en otras páginas web y otras aplicaciones web fuera significativamente más fácil.

Sin embargo, si alguna vez ha creado controles personalizados compilados en ASP.NET, sabe que hacerlo requiere una cantidad considerable de esfuerzo y presenta una serie de sutilezas y casos límites que deben manejarse cuidadosamente. Por lo tanto, vamos a renunciar a implementar una columna de botones de radio como una clase personalizada DataControlField por ahora y seguir con la opción TemplateField. Quizás tendremos la oportunidad de explorar la creación, el uso y la implementación de clases personalizadas DataControlField en un tutorial futuro.

Paso 4: Mostrar los productos del proveedor seleccionado en una página independiente

Una vez que el usuario haya seleccionado una fila GridView, es necesario mostrar los productos del proveedor seleccionado. En algunas circunstancias, es posible que deseemos mostrar estos productos en una página independiente, en otras es posible que prefieramos hacerlo en la misma página. Examinemos primero cómo mostrar los productos en una página independiente; en el paso 5 veremos cómo agregar gridView para RadioButtonField.aspx mostrar los productos del proveedor seleccionado.

Actualmente hay dos controles Web de botón en la página ListProducts y SendToProducts. Cuando se hace clic en el SendToProducts botón, queremos enviar el usuario a ~/Filtering/ProductsForSupplierDetails.aspx. Esta página se creó en el tutorial Master/Detail Filtering Across Two Pages (Filtrado de maestros y detalles entre dos páginas) y muestra los productos para el proveedor cuya SupplierID se pasa a través del campo de cadena de consulta denominado SupplierID.

Para proporcionar esta funcionalidad, cree un controlador de eventos para el SendToProducts evento Button s Click . En el paso 3 agregamos la SuppliersSelectedIndex propiedad , que devuelve el índice de la fila cuyo botón de radio está seleccionado. El objeto correspondiente SupplierID se puede recuperar de la colección de GridView DataKeys, y después se puede enviar al usuario a ~/Filtering/ProductsForSupplierDetails.aspx?SupplierID=SupplierID mediante Response.Redirect("url").

protected void SendToProducts_Click(object sender, EventArgs e)
{
    // Send the user to ~/Filtering/ProductsForSupplierDetails.aspx
    int supplierID = 
        Convert.ToInt32(Suppliers.DataKeys[SuppliersSelectedIndex].Value);
    Response.Redirect(
        "~/Filtering/ProductsForSupplierDetails.aspx?SupplierID=" 
        + supplierID);
    }
}

Este código funciona maravillosamente siempre que se seleccione uno de los botones de radio de GridView. Si, inicialmente, GridView no tiene ningún botón de radio seleccionado y el usuario hace clic en el botón SendToProducts, SuppliersSelectedIndex será -1, lo que hará que se produzca una excepción ya que -1 está fuera del rango de índices de la colección DataKeys. Sin embargo, esto no es un problema si decide actualizar el RowCreated controlador de eventos como se describe en el paso 3 para que el primer botón de radio de GridView esté seleccionado inicialmente.

Para dar cabida a un SuppliersSelectedIndex valor de -1, agregue un control Web Label a la página situada encima de GridView. Establezca su propiedad ID a ChooseSupplierMsg, su propiedad CssClass a Warning, sus propiedades EnableViewState y Visible a false, y su propiedad Text a "Elija un proveedor de la cuadrícula". La clase Warning CSS muestra texto en rojo, cursiva, negrita, fuente grande y se define en Styles.css. Al establecer las propiedades EnableViewState y Visible en false, la etiqueta no se representa excepto durante aquellos postbacks en los que la propiedad Visible del control se establece mediante programación en true.

Agregar un control web de etiqueta encima de GridView

Figura 13: Agregar un control web de etiqueta encima del GridView (haga clic para ver la imagen de tamaño completo)

A continuación, aumente el Click controlador de eventos para mostrar la ChooseSupplierMsg etiqueta si SuppliersSelectedIndex es menor que cero y redirigir al usuario a ~/Filtering/ProductsForSupplierDetails.aspx?SupplierID=SupplierID de lo contrario.

protected void SendToProducts_Click(object sender, EventArgs e)
{
    // make sure one of the radio buttons has been selected
    if (SuppliersSelectedIndex < 0)
        ChooseSupplierMsg.Visible = true;
    else
    {
        // Send the user to ~/Filtering/ProductsForSupplierDetails.aspx
        int supplierID = 
            Convert.ToInt32(Suppliers.DataKeys[SuppliersSelectedIndex].Value);
        Response.Redirect(
            "~/Filtering/ProductsForSupplierDetails.aspx?SupplierID=" 
            + supplierID);
    }
}

Visite la página en un explorador y haga clic en el SendToProducts botón antes de seleccionar un proveedor en GridView. Como muestra la figura 14, se visualiza la etiqueta ChooseSupplierMsg. A continuación, seleccione un proveedor y haga clic en el SendToProducts botón . Esto le llevará a una página que enumera los productos suministrados por el proveedor seleccionado. En la figura 15 se muestra la ProductsForSupplierDetails.aspx página cuando se seleccionó el proveedor de Bigfoot Breweries.

La etiqueta ChooseSupplierMsg se muestra si no hay ningún proveedor seleccionado

Figura 14: La ChooseSupplierMsg etiqueta se muestra si no hay ningún proveedor seleccionado (haga clic para ver la imagen de tamaño completo)

Los productos del proveedor seleccionado se muestran en ProductsForSupplierDetails.aspx

Figura 15: Los productos del proveedor seleccionado se muestran en ProductsForSupplierDetails.aspx (Haga clic para ver la imagen de tamaño completo)

Paso 5: Mostrar los productos del proveedor seleccionado en la misma página

En el paso 4 vimos cómo enviar el usuario a otra página web para mostrar los productos del proveedor seleccionado. Como alternativa, los productos del proveedor seleccionados se pueden mostrar en la misma página. Para ilustrar esto, agregaremos otro GridView a RadioButtonField.aspx para mostrar los productos del proveedor seleccionado.

Puesto que solo queremos que el GridView de productos se muestre una vez que se haya seleccionado un proveedor, agregue un control Panel Web debajo de Suppliers GridView, estableciendo su ID en ProductsBySupplierPanel y su propiedad Visible en false. En el Panel, agregue el texto Productos para el Proveedor Seleccionado, seguido de un GridView denominado ProductsBySupplier. En la etiqueta inteligente GridView, elija enlazarla a un nuevo ObjectDataSource denominado ProductsBySupplierDataSource.

Enlace ProductsBySupplier GridView a un nuevo ObjectDataSource

Figura 16: Enlazar GridView ProductsBySupplier a un nuevo objectDataSource (haga clic para ver la imagen de tamaño completo)

A continuación, configure ObjectDataSource para usar la ProductsBLL clase . Puesto que solo queremos recuperar esos productos proporcionados por el proveedor seleccionado, especifique que objectDataSource debe invocar el GetProductsBySupplierID(supplierID) método para recuperar sus datos. Seleccione (Ninguno) en las listas desplegables de las pestañas UPDATE, INSERT y DELETE.

Configurar ObjectDataSource para usar el método GetProductsBySupplierID(supplierID)

Figura 17: Configurar objectDataSource para usar el método (GetProductsBySupplierID(supplierID) la imagen de tamaño completo)

Establezca las listas de Drop-Down en (Ninguno) en las pestañas UPDATE, INSERT y DELETE.

Figura 18: Establecer las listas de Drop-Down en (Ninguno) en las pestañas UPDATE, INSERT y DELETE (Haga clic para ver la imagen de tamaño completo).

Después de configurar las pestañas SELECT, UPDATE, INSERT y DELETE, haga clic en Siguiente. Dado que el GetProductsBySupplierID(supplierID) método espera un parámetro de entrada, el Asistente para crear origen de datos nos pide que especifiquemos el origen para el valor del parámetro.

Aquí tenemos un par de opciones para especificar el origen del valor del parámetro. Podríamos usar el objeto Parameter predeterminado y asignar mediante programación el valor de la propiedad SuppliersSelectedIndex a la propiedad DefaultValue del objeto Parameter en el controlador de eventos Selecting del ObjectDataSource. Consulte de nuevo el tutorial Configuración mediante programación de los valores de parámetros de ObjectDataSource para un repaso sobre la asignación de valores mediante programación a los parámetros de ObjectDataSource.

Como alternativa, podemos usar un ControlParameter y hacer referencia a la propiedad del Suppliers GridView (SelectedValue) (vea la Figura 19). La propiedad GridView s SelectedValue devuelve el DataKey valor correspondiente a la SelectedIndex propiedad . Para que esta opción funcione, es necesario establecer mediante programación la propiedad GridView s SelectedIndex en la fila seleccionada cuando se hace clic en el ListProducts botón. Como ventaja adicional, al establecer el SelectedIndex, el registro seleccionado adoptará el SelectedRowStyle definido en el DataWebControls Tema (fondo amarillo).

Usar un ControlParameter para especificar el valor SelectedValue de GridView como origen de parámetros

Figura 19: Usar un controlParameter para especificar el valor SelectedValue de GridView como origen del parámetro (haga clic para ver la imagen de tamaño completo)

Al completar el asistente, Visual Studio agregará automáticamente campos para los campos de datos del producto. Elimine todos los BoundFields excepto ProductName, CategoryName, y UnitPrice, y cambie las propiedades de HeaderText a Producto, Categoría y Precio. Configure el BoundField UnitPrice para que su valor esté en formato de moneda. Después de realizar estos cambios, el marcado declarativo de Panel, GridView y ObjectDataSource debe ser similar al siguiente:

<asp:Panel runat="server" ID="ProductsBySupplierPanel" Visible="False">
    <h3>
        Products for the Selected Supplier</h3>
    <p>
        <asp:GridView ID="ProductsBySupplier" runat="server" 
            AutoGenerateColumns="False" DataKeyNames="ProductID"
            DataSourceID="ProductsBySupplierDataSource" EnableViewState="False">
            <Columns>
                <asp:BoundField DataField="ProductName" HeaderText="Product" 
                    SortExpression="ProductName" />
                <asp:BoundField DataField="CategoryName" HeaderText="Category" 
                    ReadOnly="True" SortExpression="CategoryName" />
                <asp:BoundField DataField="UnitPrice" DataFormatString="{0:c}" 
                    HeaderText="Price" HtmlEncode="False" 
                    SortExpression="UnitPrice" />
            </Columns>
        </asp:GridView>
        <asp:ObjectDataSource ID="ProductsBySupplierDataSource" runat="server" 
            OldValuesParameterFormatString="original_{0}"
            SelectMethod="GetProductsBySupplierID" TypeName="ProductsBLL">
            <SelectParameters>
                <asp:ControlParameter ControlID="Suppliers" Name="supplierID" 
                    PropertyName="SelectedValue" Type="Int32" />
            </SelectParameters>
        </asp:ObjectDataSource>
    </p>
</asp:Panel>

Para completar este ejercicio, es necesario establecer la propiedad SelectedIndex del GridView a SelectedSuppliersIndex y la propiedad ProductsBySupplierPanel del panel Visible a true cuando se hace clic en el botón ListProducts. Para ello, cree un controlador de eventos para el ListProducts evento del control web Button Click y agregue el código siguiente.

protected void ListProducts_Click(object sender, EventArgs e)
{
    // make sure one of the radio buttons has been selected
    if (SuppliersSelectedIndex < 0)
    {
        ChooseSupplierMsg.Visible = true;
        ProductsBySupplierPanel.Visible = false;
    }
    else
    {
        // Set the GridView's SelectedIndex
        Suppliers.SelectedIndex = SuppliersSelectedIndex;
        // Show the ProductsBySupplierPanel panel
        ProductsBySupplierPanel.Visible = true;
    }
}

Si no se ha seleccionado un proveedor en GridView, se muestra la etiqueta ChooseSupplierMsg y se oculta el panel ProductsBySupplierPanel. De lo contrario, si se ha seleccionado un proveedor, ProductsBySupplierPanel se muestra y se actualiza la propiedad GridView s SelectedIndex .

En la figura 20 se muestran los resultados después de seleccionar el proveedor bigfoot Breweries y se ha realizado clic en el botón Mostrar productos en la página.

Los productos suministrados por las fábricas de cervezas bigfoot se enumeran en la misma página

Figura 20: Los productos suministrados por bigfoot Breweries aparecen en la misma página (haga clic para ver la imagen de tamaño completo)

Resumen

Como se describe en el tutorial Master/Detail Using a Selectable Master GridView with a Details DetailView, los registros se pueden seleccionar desde el GridView mediante un CommandField, cuya propiedad ShowSelectButton está configurada en true. Pero CommandField muestra sus botones como botones de presión normales, vínculos o imágenes. Una interfaz de usuario alternativa para la selección de filas es proporcionar un botón de radio o una casilla de verificación en cada fila de GridView. En este tutorial hemos examinado cómo agregar una columna de botones de radio.

Desafortunadamente, agregar una columna de botones de radio no es tan simple o directo como podría uno esperar. No hay ningún RadioButtonField integrado que se pueda agregar en el clic de un botón y el uso del control Web RadioButton dentro de un TemplateField presenta su propio conjunto de problemas. Al final, para proporcionar este tipo de interfaz, tenemos que crear una clase personalizada DataControlField o recurrir a insertar el CÓDIGO HTML adecuado en un TemplateField durante el RowCreated evento.

Después de explorar cómo agregar una columna de botones de radio, centremos nuestra atención en agregar una columna de casillas. Con una columna de casillas, un usuario puede seleccionar una o varias filas de GridView y, a continuación, realizar alguna operación en todas las filas seleccionadas (por ejemplo, seleccionar un conjunto de correos electrónicos de un cliente de correo electrónico basado en web y, a continuación, elegir eliminar todos los correos electrónicos seleccionados). En el siguiente tutorial veremos cómo agregar dicha columna.

¡Feliz programación!

Acerca del autor

Scott Mitchell, autor de siete libros de ASP/ASP.NET y fundador de 4GuysFromRolla.com, ha estado trabajando con tecnologías web de Microsoft desde 1998. Scott trabaja como consultor independiente, entrenador y escritor. Su último libro es Sams Teach Yourself ASP.NET 2.0 en 24 horas. Se puede contactar con él en mitchell@4GuysFromRolla.com.

Agradecimientos especiales a

Esta serie de tutoriales contó con la revisión de muchos revisores que fueron de gran ayuda. El revisor principal de este tutorial ha sido David Suru. ¿Le interesa revisar mis próximos artículos de MSDN? Si es así, mándame un mensaje a mitchell@4GuysFromRolla.com.