Compartir a través de


Agregar y responder a los botones en un control GridView (C#)

por Scott Mitchell

Descargar PDF

En este tutorial, veremos cómo agregar botones personalizados, tanto a una plantilla como a los campos de un control GridView o DetailsView. En concreto, vamos a crear una interfaz con un control FormView que permita al usuario pasar páginas para ver los proveedores.

Introducción

Aunque muchos escenarios de informes implican acceso de solo lectura a los datos del informe, no es raro que los informes incluyan la capacidad de realizar acciones basadas en los datos mostrados. Normalmente, esto implica agregar un control web Button, LinkButton o ImageButton con cada registro mostrado en el informe que, cuando se haga clic en él, genere un postback e invoque código del lado servidor. La edición y eliminación de los datos en una modalidad de registro por registro es el ejemplo más común. De hecho, como vimos a partir del tutorial Información general sobre la inserción, actualización y eliminación de datos, la edición y la eliminación son tan comunes que los controles GridView, DetailsView y FormView puedan admitir dicha funcionalidad sin necesidad de escribir una sola línea de código.

Además de los botones Editar y Eliminar, los controles GridView, DetailsView y FormView también pueden incluir Botones, LinkButtons o ImageButtons que, cuando se haga clic en ellos, realicen alguna lógica personalizada del lado servidor. En este tutorial, veremos cómo agregar botones personalizados, tanto a una plantilla como a los campos de un control GridView o DetailsView. En concreto, vamos a crear una interfaz con un control FormView que permita al usuario pasar páginas para ver los proveedores. Para un proveedor determinado, el control FormView mostrará información sobre el proveedor junto con un control web de botón que, si se hace clic en él, marcará todos sus productos asociados como descontinuados. Además, un GridView enumera esos productos ofrecidos por el proveedor seleccionado, con cada fila que contiene botones de aumentar precio y precio de descuento que, si se hace clic en ellos, aumentan o reducen el UnitPrice del producto en un 10 %(vea la figura 1).

FormView y GridView contienen botones que realizan acciones personalizadas

Figura 1: FormView y GridView contienen botones que realizan acciones personalizadas (haga clic para ver la imagen a tamaño completo)

Paso 1: Agregar las páginas web de tutoriales sobre botones

Antes de ver cómo agregar botones personalizados, primero tomemos un momento para crear las páginas ASP.NET, que necesitaremos para este tutorial, en nuestro proyecto de sitio web. Empiece agregando una nueva carpeta denominada CustomButtons. Después, agregue estas dos páginas ASP.NET a esa carpeta, asegurándose de asociar cada página a la página maestra Site.master:

  • Default.aspx
  • CustomButtons.aspx

Agregar las páginas ASP.NET para los tutoriales sobre botones personalizados

Figura 2: Agregar las páginas ASP.NET para los tutoriales sobre botones personalizados

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

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

Figura 3: Agregue el control de usuario SectionLevelTutorialListing.ascx a Default.aspx (haga clic aquí para ver la imagen a tamaño completo)

Por último, agregue las siguientes páginas como entradas al archivo Web.sitemap. En concreto, agregue el siguiente marcado después de la paginación y ordenación <siteMapNode>:

<siteMapNode
    title="Adding Custom Buttons"
    description="Samples of Reports that Include Buttons for Performing
                  Server-Side Actions"
    url="~/CustomButtons/Default.aspx">
    <siteMapNode
        title="Using ButtonFields and Buttons in Templates"
        description="Examines how to add custom Buttons, LinkButtons,
                      or ImageButtons as ButtonFields or within templates."
        url="~/CustomButtons/CustomButtons.aspx" />
</siteMapNode>

Después de actualizar Web.sitemap, dedique un momento a ver el sitio web de 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 la entrada para el tutorial sobre botones personalizados

Figura 4: el mapa del sitio ahora incluye la entrada para el tutorial sobre botones personalizados

Paso 2: Agregar un control FormView que enumere los proveedores

Para empezar a trabajar con este tutorial, agregue el control FormView que enumere los proveedores. Como se describe en la introducción, este control FormView permitirá al usuario pasar páginas para ver los proveedores, mostrando los productos ofrecidos por el proveedor en un control GridView. Además, este control FormView incluirá un botón que, cuando se haga clic en él, marcará todos los productos del proveedor como descontinuados. Antes de preocuparnos por agregar el botón personalizado al control FormView, primero vamos a crear el FormView para que muestre la información del proveedor.

Para empezar, abra la página CustomButtons.aspx en la carpeta CustomButtons. Agregue un control FormView a la página arrastrándolo desde el cuadro de herramientas al Diseñador y establezca su propiedad ID en Suppliers. En la etiqueta inteligente de FormView, elija crear un objeto ObjectDataSource denominado SuppliersDataSource.

Crear un nuevo ObjectDataSource denominado SuppliersDataSource

Figura 5: Cree un nuevo ObjectDataSource denominado SuppliersDataSource (Haga clic para ver la imagen de tamaño completo)

Configure este nuevo ObjectDataSource de modo que realice consultas desde el método GetSuppliers() de la clase SuppliersBLL (vea la figura 6). Puesto que el control FormView no proporciona una interfaz para actualizar la información del proveedor, seleccione la opción (None) en la lista desplegable de la pestaña UPDATE.

Configurar el origen de datos para usar el método GetSuppliers() de la clase SuppliersBLL

Figura 6: Configure el origen de datos para usar el método GetSuppliers() de la clase SuppliersBLL (haga clic para ver la imagen a tamaño completo)

Después de configurar ObjectDataSource, Visual Studio generará un InsertItemTemplate,EditItemTemplate y ItemTemplate para el control FormView. Quite el InsertItemTemplate y EditItemTemplate, y modifique el ItemTemplate para que muestre solo el nombre de empresa y el número de teléfono del proveedor. Por último, active la compatibilidad con la paginación para el control FormView activando la casilla Habilitar paginación desde su etiqueta inteligente (o estableciendo su propiedad AllowPaging en True). Después de estos cambios, el marcado declarativo de la página debe tener un aspecto similar al siguiente:

<asp:FormView ID="Suppliers" runat="server" DataKeyNames="SupplierID"
    DataSourceID="SuppliersDataSource" EnableViewState="False" AllowPaging="True">
    <ItemTemplate>
        <h3>
            <asp:Label ID="CompanyName" runat="server"
                Text='<%# Bind("CompanyName") %>' />
        </h3>
        <b>Phone:</b>
        <asp:Label ID="PhoneLabel" runat="server" Text='<%# Bind("Phone") %>' />
    </ItemTemplate>
</asp:FormView>
<asp:ObjectDataSource ID="SuppliersDataSource" runat="server"
    OldValuesParameterFormatString="original_{0}"
    SelectMethod="GetSuppliers" TypeName="SuppliersBLL">
</asp:ObjectDataSource>

En la figura 7, se muestra la página CustomButtons.aspx cuando se visualiza en un explorador.

FormView enumera los campos CompanyName y Phone del proveedor seleccionado actualmente

Figura 7: FormView enumera los campos CompanyName y Phone del proveedor seleccionado actualmente (haga clic para ver la imagen de tamaño completo)

Paso 3: Agregar un control GridView que enumere los productos del proveedor seleccionado

Antes de agregar el botón Discontinue All Products a la plantilla de FormView, primero vamos a agregar un control GridView debajo de FormView que enumere los productos proporcionados por el proveedor seleccionado. Para ello, agregue un control GridView a la página, establezca su propiedad ID en SuppliersProducts y cree un nuevo ObjectDataSource denominado SuppliersProductsDataSource.

Crear un nuevo ObjectDataSource denominado SuppliersProductsDataSource

Figura 8: Cree un nuevo ObjectDataSource denominado SuppliersProductsDataSource (haga clic para ver la imagen de tamaño completo)

Configure este ObjectDataSource para usar el método GetProductsBySupplierID(supplierID) de la clase ProductsBLL (vea la figura 9). Aunque GridView permitirá que se ajuste el precio de un producto, no usará la edición integrada ni eliminará características de GridView. Por lo tanto, podemos establecer la lista desplegable en (None) para las pestaña UPDATE, INSERT y DELETE de ObjectDataSource.

Configurar el origen de datos para usar el método GetProductsBySupplierID(supplierID) de la clase ProductsBLL

Figura 9: Configure ObjectDataSource para usar el método GetProductsBySupplierID(supplierID) de la clase ProductsBLL (haga clic para ver la imagen a tamaño completo)

Dado que el método GetProductsBySupplierID(supplierID) acepta un parámetro de entrada, el asistente ObjectDataSource nos pide el origen de este valor de parámetro. Para pasar el valor SupplierID desde FormView, establezca la lista desplegable Origen de parámetros en Control y la lista desplegable ControlID en Suppliers (el id. del FormView creado en el paso 2).

Indicar que el parámetro supplierID debe proceder del control FormView proveedores

Figura 10: Indique que el parámetro supplierID debe provenir del control Suppliers de FormView (haga clic para ver la imagen de tamaño completo)

Después de completar el asistente ObjectDataSource, el control GridView contendrá un BoundField o CheckBoxField para cada uno de los campos de datos del producto. Vamos a recortar esto para mostrar solo los BoundFields ProductName y UnitPrice junto con el CheckBoxField Discontinued; además, vamos a dar formato al BoundField UnitPrice de modo que su texto tenga el formato de moneda. El marcado declarativo del control GridView y del ObjectDataSource de SuppliersProductsDataSource debe tener un aspecto similar al siguiente:

<asp:GridView ID="SuppliersProducts" AutoGenerateColumns="False"
    DataKeyNames="ProductID" DataSourceID="SuppliersProductsDataSource"
    EnableViewState="False" runat="server">
    <Columns>
        <asp:BoundField DataField="ProductName" HeaderText="Product"
            SortExpression="ProductName" />
        <asp:BoundField DataField="UnitPrice" HeaderText="Price"
            SortExpression="UnitPrice" DataFormatString="{0:C}"
            HtmlEncode="False" />
        <asp:CheckBoxField DataField="Discontinued" HeaderText="Discontinued"
            SortExpression="Discontinued" />
    </Columns>
</asp:GridView>
<asp:ObjectDataSource ID="SuppliersProductsDataSource" runat="server"
    OldValuesParameterFormatString="original_{0}"
    SelectMethod="GetProductsBySupplierID" TypeName="ProductsBLL">
    <SelectParameters>
        <asp:ControlParameter ControlID="Suppliers" Name="supplierID"
            PropertyName="SelectedValue" Type="Int32" />
    </SelectParameters>
</asp:ObjectDataSource>

En este momento, nuestro tutorial muestra un informe maestros y de detalles, lo que permite al usuario elegir un proveedor del FormView en la parte superior para ver los productos ofrecidos por ese proveedor a través de GridView en la parte inferior. En la figura 11, se muestra una captura de pantalla de esta página al seleccionar el proveedor Tokyo Traders en el FormView.

Los productos del proveedor seleccionado se muestran en GridView

Figura 11: Se muestran los productos del proveedor seleccionado en GridView (haga clic para ver la imagen de tamaño completo)

Paso 4: Crear métodos DAL y BLL para descontinuar todos los productos de un proveedor

Antes de poder agregar un botón a FormView que, cuando se haga clic él, descontinúe todos los productos del proveedor, primero necesitamos agregar un método a la DAL y la BLL que realice esta acción. En concreto, este método se denominará DiscontinueAllProductsForSupplier(supplierID). Cuando se hace clic en el botón de FormView, invocaremos este método en la capa lógica de negocios (BLL), pasando el SupplierID del proveedor seleccionado; la BLL llamará al método capa de acceso a datos (DAL) correspondiente, que emitirá una instrucción UPDATE a la base de datos que descontinúa los productos del proveedor especificado.

Como hemos hecho en nuestros tutoriales anteriores, vamos a usar un enfoque de abajo hacia arriba, comenzando por crear el método DAL, luego el método BLL y, por último, vamos a implementar la funcionalidad en la página ASP.NET. Abra el conjunto de datos con tipo Northwind.xsd en la carpeta App_Code/DAL y agregue un nuevo método a ProductsTableAdapter (haga clic con el botón derecho en ProductsTableAdapter y elija Agregar consulta). Al hacerlo, aparecerá el Asistente para configuración de consultas de TableAdapter, que nos guiará por el proceso de agregar el nuevo método. Empiece por indicar que el método DAL usará una instrucción SQL ad hoc.

Crear el método DAL mediante una instrucción SQL ad hoc

Figura 12: crear el método mediante una instrucción SQL ad hoc (haga clic para ver la imagen a tamaño completo)

Luego, el asistente nos pide información sobre el tipo de consulta que se va a crear. Dado que el método DiscontinueAllProductsForSupplier(supplierID) tendrá que actualizar la tabla Products de la base de datos, estableciendo el campo Discontinued en 1 para todos los productos ofrecidos por el supplierID especificado, es necesario crear una consulta que actualice los datos.

Elegir el tipo de consulta UPDATE

Figura 13: Elija el tipo de consulta UPDATE (haga clic para ver la imagen de tamaño completo)

La siguiente pantalla del asistente proporciona la instrucción UPDATE existente de TableAdapter, que actualiza cada uno de los campos definidos en la DataTable Products. Reemplace este texto de consulta por la siguiente instrucción:

UPDATE [Products] SET
   Discontinued = 1
WHERE SupplierID = @SupplierID

Después de escribir esta consulta y hacer clic en Siguiente, la última pantalla del asistente solicita el nombre del nuevo método; use DiscontinueAllProductsForSupplier. Para finalizar el asistente, haga clic en el botón Finalizar. Al volver al Diseñador del conjuntos de datos, debería ver un nuevo método en el ProductsTableAdapter denominado DiscontinueAllProductsForSupplier(@SupplierID).

Asignar al nuevo método DAL el nombre DiscontinueAllProductsForSupplier

Figura 14: asignar el nombre al nuevo método DAL DiscontinueAllProductsForSupplier (haga clic para ver la imagen de tamaño completo)

Con el método DiscontinueAllProductsForSupplier(supplierID) creado en la capa de acceso a datos, la siguiente tarea consiste en crear el método DiscontinueAllProductsForSupplier(supplierID) en la capa lógica de negocios. Para ello, abra el archivo de clase ProductsBLL y agregue lo siguiente:

public int DiscontinueAllProductsForSupplier(int supplierID)
{
    return Adapter.DiscontinueAllProductsForSupplier(supplierID);
}

Este método simplemente llama al método DiscontinueAllProductsForSupplier(supplierID) en la DAL y pasa el valor del parámetro supplierID proporcionado. Si hubiera alguna regla de negocios que solo permitiera que los productos de un proveedor se descontinúen en determinadas circunstancias, esas normas se deben aplicar aquí, en la BLL.

Nota:

A diferencia de las sobrecargas de UpdateProduct de la clase ProductsBLL, la firma del método DiscontinueAllProductsForSupplier(supplierID) no incluye el atributo DataObjectMethodAttribute (<System.ComponentModel.DataObjectMethodAttribute(System.ComponentModel.DataObjectMethodType.Update, Boolean)>). Esto excluye el método DiscontinueAllProductsForSupplier(supplierID) de la lista desplegable en la pestaña UPDATE del Asistente para configurar orígenes de datos de ObjectDataSource. He omitido este atributo porque llamaremos al método DiscontinueAllProductsForSupplier(supplierID) directamente desde un controlador de eventos en la página de ASP.NET.

Paso 5: Agregar un botón “Discontinue All Products” a FormView

Con el método DiscontinueAllProductsForSupplier(supplierID) en las BLL y DAL completado, el paso final para agregar la capacidad de descontinuar todos los productos para el proveedor seleccionado es agregar un control web de botón al control al ItemTemplate de FormView. Vamos a agregar este tipo de botón debajo del número de teléfono del proveedor con el texto del botón, Discontinue All Products y un valor de propiedad de ID de DiscontinueAllProductsForSupplier. Para agregar este control web de botón a través del Diseñador, haga clic en el vínculo Edit Templates de la etiqueta inteligente de FormView (vea la figura 15) o directamente en la sintaxis declarativa.

Agregar un control web de botón con texto

Figura 15: Agregue un control web de botón Discontinue All Products a ItemTemplate de FormView (haga clic para ver la imagen de tamaño completo)

Cuando un usuario que visita la página hace clic en el botón, se activa un postback y se desencadena el evento ItemCommand de FormView. Para ejecutar código personalizado en respuesta a este botón en el que se hace clic, podemos crear un controlador de eventos para este evento. Sin embargo, hay que comprende que el evento ItemCommand se activa cada vez que se hace clic en cualquier control web Botón, LinkButton o ImageButton en FormView. Esto significa que cuando el usuario se mueve de una página a otra en FormView, el evento ItemCommand se activa; lo mismo cuando el usuario hace clic en Nuevo, Editar o Eliminar en un FormView que admite la inserción, actualización o eliminación.

Dado que se ItemCommand activa independientemente del botón en el que se hace clic, en el controlador de eventos, necesitamos una manera de determinar si se hizo clic en el botón Discontinue All Products o en otro botón. Para ello, podemos establecer la propiedad CommandName del control web de botón en algún valor de identificación. Cuando se hace clic en el botón, este valor CommandName se pasa al controlador de eventos ItemCommand, lo que nos permite determinar si se hizo clic en el botón Discontinue All Products. Establezca la propiedad la propiedad CommandName del botón Discontinue All Products en DiscontinueProducts.

Por último, vamos a usar un cuadro de diálogo de confirmación del lado cliente para asegurarnos de que el usuario realmente quiere descontinuar los productos del proveedor seleccionado. Como vimos en el tutorial Agregar confirmación del cliente al eliminar, esto se puede lograr con un poco de JavaScript. En concreto, establezca la propiedad OnClientClick del control web de botón en return confirm('This will mark _all_ of this supplier\'s products as discontinued. Are you certain you want to do this?');.

Después de realizar estos cambios, la sintaxis declarativa de FormView debe ser similar a la siguiente:

<asp:FormView ID="Suppliers" runat="server" DataKeyNames="SupplierID"
    DataSourceID="SuppliersDataSource" EnableViewState="False"
    AllowPaging="True">
    <ItemTemplate>
        <h3><asp:Label ID="CompanyName" runat="server"
            Text='<%# Bind("CompanyName") %>'></asp:Label></h3>
        <b>Phone:</b>
        <asp:Label ID="PhoneLabel" runat="server" Text='<%# Bind("Phone") %>' />
        <br />
        <asp:Button ID="DiscontinueAllProductsForSupplier" runat="server"
            CommandName="DiscontinueProducts" Text="Discontinue All Products"
            OnClientClick="return confirm('This will mark _all_ of this supplier\'s
                products as discontinued. Are you certain you want to do this?');" />
    </ItemTemplate>
</asp:FormView>

Después, cree un controlador de eventos para el evento ItemCommand de FormView. En este controlador de eventos, es necesario determinar primero si se hizo clic en el botón Discontinue All Products. Si es así, debemos crear una instancia de la clase ProductsBLL e invocar su método DiscontinueAllProductsForSupplier(supplierID), pasando el SupplierID del FormView seleccionado:

protected void Suppliers_ItemCommand(object sender, FormViewCommandEventArgs e)
{
    if (e.CommandName.CompareTo("DiscontinueProducts") == 0)
    {
        // The "Discontinue All Products" Button was clicked.
        // Invoke the ProductsBLL.DiscontinueAllProductsForSupplier(supplierID) method
        // First, get the SupplierID selected in the FormView
        int supplierID = (int)Suppliers.SelectedValue;
        // Next, create an instance of the ProductsBLL class
        ProductsBLL productInfo = new ProductsBLL();
        // Finally, invoke the DiscontinueAllProductsForSupplier(supplierID) method
        productInfo.DiscontinueAllProductsForSupplier(supplierID);
    }
}

Tenga en cuenta que se puede acceder al SupplierID del proveedor seleccionado actual en FormView mediante la propiedad SelectedValue de FormView. La propiedad SelectedValue devuelve el primer valor de clave de datos del registro que se muestra en FormView. La propiedad DataKeyNames de FormView, que indica los campos de datos de los que se extraen los valores de clave de datos, se ha establecido en SupplierID automáticamente en Visual Studio al enlazar ObjectDataSource a FormView en el paso 2.

Con el controlador de eventosItemCommand creado, tómese un momento para probar la página. Vaya al proveedor Cooperativa de Quesos “Las Cabras” (es el quinto proveedor en el FormView para mí). Este proveedor ofrece dos productos, Queso Cabrales y Queso Manchego La Pastora, ambos no descontinuados.

Imagine que la Cooperativa de Quesos “Las Cabras” ha dejado de operar y, por lo tanto, sus productos deben descontinuarse. Haga clic en el botón Descontinuar todos los productos. Se mostrará el cuadro de diálogo de confirmar del lado cliente (véase la Figura 16).

Cooperativa de Quesos Las Cabras suministra dos productos activos

Figura 16: Cooperativa de Quesos Las Cabras ofrece dos productos activos (haga clic para ver la imagen de tamaño completo)

Si hace clic en OK en el cuadro de diálogo de confirmación del lado cliente, el envío del formulario continuará, lo que generará un postback en el que se activará el evento ItemCommand de FormView. El controlador de eventos que hemos creado se ejecutará, invocando el método DiscontinueAllProductsForSupplier(supplierID) y descontinuando los productos Queso Cabrales y Queso Manchego La Pastora.

Si ha deshabilitado el estado de vista de GridView, GridView se está rebotando en el almacén de datos subyacente en cada postback y, por lo tanto, se actualizará inmediatamente para reflejar que estos dos productos ahora están descontinuados (consulte la figura 17). Sin embargo, si no ha deshabilitado el estado de visualización en el GridView, deberá volver a enlazar manualmente los datos al GridView después de realizar este cambio. Para ello, simplemente realice una llamada al método DataBind() de GridView inmediatamente después de invocar el método DiscontinueAllProductsForSupplier(supplierID).

Después de hacer clic en el botón Discontinue All Products, los productos del proveedor se actualizan en consecuencia

Figura 17: Después de hacer clic en el botón Discontinue All Products, los productos del proveedor se actualizan en consecuencia (haga clic para ver la imagen de tamaño completo)

Paso 6: Crear una sobrecarga UpdateProduct en la capa lógica de negocios para ajustar el precio de un producto

Al igual que con el botón Discontinue All Products en el FormView, para agregar botones a fin de aumentar y reducir el precio de un producto en el GridView, primero necesitamos agregar los métodos de capa de acceso a datos y capa de lógica de negocios adecuados. Puesto que ya tenemos un método que actualiza una sola fila de producto en la DAL, podemos proporcionar esta funcionalidad mediante la creación de una nueva sobrecarga para el método UpdateProduct en la BLL.

Nuestras sobrecargas pasadas de UpdateProduct han incluido algunas combinaciones de campos de producto como valores de entrada escalares y, luego, se han actualizado solo esos campos para el producto especificado. Para esta sobrecarga, vamos desviarnos ligeramente de este estándar y, en su lugar, vamos a pasar el ProductID del producto y el porcentaje según el que se ajustará el UnitPrice (en lugar de pasar el nuevo UnitPrice ajustado). Este enfoque simplificará el código que necesitamos escribir en la clase de código subyacente de la página ASP.NET, ya que no tenemos que molestarnos en determinar el UnitPrice del producto actual.

A continuación, se muestra la sobrecarga UpdateProduct para este tutorial:

public bool UpdateProduct(decimal unitPriceAdjustmentPercentage, int productID)
{
    Northwind.ProductsDataTable products = Adapter.GetProductByProductID(productID);
    if (products.Count == 0)
        // no matching record found, return false
        return false;
    Northwind.ProductsRow product = products[0];
    // Adjust the UnitPrice by the specified percentage (if it's not NULL)
    if (!product.IsUnitPriceNull())
        product.UnitPrice *= unitPriceAdjustmentPercentage;
    // Update the product record
    int rowsAffected = Adapter.Update(product);
    // Return true if precisely one row was updated, otherwise false
    return rowsAffected == 1;
}

Esta sobrecarga recupera información sobre el producto especificado a través del método GetProductByProductID(productID) de la DAL. Luego, comprueba si el UnitPrice del producto tiene asignado un valor de base de datos NULL. Si es así, el precio se deja sin cambios. Sin embargo, si no hay ningún valor NULL UnitPrice, el método actualiza el UnitPrice del producto según el porcentaje especificado (unitPriceAdjustmentPercent).

Paso 7: Agregar los botones Increase y Decrease al GridView

El GridView (y el DetailsView) se componen de una colección de campos. Además de BoundFields, CheckBoxFields y TemplateFields, ASP.NET incluye ButtonField, que, como su nombre implica, se representa como una columna con un Button, LinkButton o ImageButton para cada fila. Al igual que FormView, al hacer clic en cualquier botón entre los botones de paginación de GridView, Editar o Eliminar, ordenar botones, etc., se genera un postback y el evento RowCommand de GridView.

ButtonField tiene una propiedad CommandName que asigna el valor especificado a cada una de las propiedades CommandName de sus botones. Al igual que con FormView, el controlador de eventos RowCommand usa el valor CommandName para determinar en qué botón se hizo clic.

Vamos a agregar dos nuevos ButtonFields a GridView, uno con un texto de botón Price +10% y el otro con el texto Price -10%. Para agregar estos ButtonFields, haga clic en el vínculo Editar columnas de la etiqueta inteligente de GridView, seleccione el tipo de campo ButtonField de la lista de la parte superior izquierda y haga clic en el botón Agregar.

Agregar dos ButtonFields a GridView

Figura 18: agregar dos ButtonFields a GridView

Mueva los dos ButtonFields para que aparezcan como los dos primeros campos GridView. A continuación, establezca las propiedades Text de estos dos ButtonFields en Precio +10% y Precio -10% y las propiedades CommandName en IncreasePrice y DecreasePrice, respectivamente. De forma predeterminada, un ButtonField representa su columna de botones como LinkButtons. Sin embargo, esto se puede cambiar a través de la propiedad ButtonType de ButtonField. Vamos a representar estos dos ButtonFields como botones de inserción normales; por lo tanto, establezca la propiedad ButtonType en Button. En la figura 19, se muestra el cuadro de diálogo Campos después de realizar estos cambios; luego, se muestra el marcado declarativo de GridView.

Configurar las propiedades ButtonFields Text, CommandName y ButtonType

Figura 19: Configure las propiedades Text, CommandName y ButtonType de ButtonFields

<asp:GridView ID="SuppliersProducts" runat="server" AutoGenerateColumns="False"
    DataKeyNames="ProductID" DataSourceID="SuppliersProductsDataSource"
    EnableViewState="False">
    <Columns>
        <asp:ButtonField ButtonType="Button" CommandName="IncreasePrice"
            Text="Price +10%" />
        <asp:ButtonField ButtonType="Button" CommandName="DecreasePrice"
            Text="Price -10%" />
        <asp:BoundField DataField="ProductName" HeaderText="Product"
            SortExpression="ProductName" />
        <asp:BoundField DataField="UnitPrice" HeaderText="Price"
            SortExpression="UnitPrice" DataFormatString="{0:C}"
            HtmlEncode="False" />
        <asp:CheckBoxField DataField="Discontinued" HeaderText="Discontinued"
            SortExpression="Discontinued" />
    </Columns>
</asp:GridView>

Con estos ButtonFields creados, el último paso es crear un controlador de eventos para el evento RowCommand de GridView. Este controlador de eventos, si se desencadena porque se hizo clic en los botones Precio +10 % o Precio -10 %, debe determinar el ProductID para la fila cuyo botón se hizo clic y, a continuación, invocar el método UpdateProduct de clase ProductsBLL, pasando el ajuste de porcentaje de UnitPrice adecuado junto con ProductID. Este código realiza las tareas siguientes:

protected void SuppliersProducts_RowCommand(object sender, GridViewCommandEventArgs e)
{
    if (e.CommandName.CompareTo("IncreasePrice") == 0 ||
        e.CommandName.CompareTo("DecreasePrice") == 0)
    {
        // The Increase Price or Decrease Price Button has been clicked
        // Determine the ID of the product whose price was adjusted
        int productID =
            (int)SuppliersProducts.DataKeys[Convert.ToInt32(e.CommandArgument)].Value;
        // Determine how much to adjust the price
        decimal percentageAdjust;
        if (e.CommandName.CompareTo("IncreasePrice") == 0)
            percentageAdjust = 1.1M;
        else
            percentageAdjust = 0.9M;

        // Adjust the price
        ProductsBLL productInfo = new ProductsBLL();
        productInfo.UpdateProduct(percentageAdjust, productID);
    }
}

Para determinar el ProductID de la fila en cuyo botón Precio +10% o Precio -10% se hizo clic, necesitamos consultar la colección DataKeys de GridView. Esta colección contiene los valores de los campos especificados en la propiedad DataKeyNames para cada fila de GridView. Dado que Visual Studio estableció la propiedad DataKeyNames de GridView en ProductID al enlazar ObjectDataSource al GridView, DataKeys(rowIndex).Value proporciona el ProductID para el rowIndex especificado.

El ButtonField pasa automáticamente el rowIndex de la fila en cuyo botón se hizo clic a través del parámetro e.CommandArgument. Por lo tanto, para determinar el ProductID para la fila en cuyo botón Precio +10% o Precio -10% se hizo clic, usamos: Convert.ToInt32(SuppliersProducts.DataKeys(Convert.ToInt32(e.CommandArgument)).Value).

Al igual que con el botón Discontinue All Products, si ha deshabilitado el estado de vista de GridView, el GridView se rebotando al almacén de datos subyacente en cada postback y, por lo tanto, se actualizará inmediatamente para reflejar un cambio de precio que se produce al hacer clic en cualquiera de los botones. Sin embargo, si no ha deshabilitado el estado de visualización en el GridView, deberá volver a enlazar manualmente los datos al GridView después de realizar este cambio. Para ello, simplemente realice una llamada al método DataBind() de GridView inmediatamente después de invocar el método UpdateProduct.

En la figura 20 se muestra la página al ver los productos proporcionados Grandma Kelly's Homestead. En la figura 21 se muestran los resultados después de que se haya hecho clic en el botón Precio +10% dos veces para la Grandma's Boysenberry Spread y el botón Precio -10% una vez para Northwoods Cranberry Sauce.

GridView incluye los botones Price +10% y Price -10%

Figura 20: GridView incluye el precio +10% y el precio -10% botones (haga clic para ver la imagen a tamaño completo)

Los precios del primer y el tercer producto se han actualizado a través de los botones Price +10% y Price -10%

Figura 21: los precios del primer y el tercer producto se han actualizado a través de los botones Precio +10% y Precio -10% (Haga clic para ver la imagen a tamaño completo)

Nota:

El GridView (y DetailsView) también pueden tener Buttons, LinkButtons o ImageButtons agregados a sus TemplateFields. Al igual que con BoundField, cuando se hace clic en estos botones, se generará un postback y el evento RowCommand de GridView. Sin embargo, al agregar botones en un TemplateField, el CommandArgument del botón no se establece automáticamente en el índice de la fila, como cuando se usan ButtonFields. Si necesita determinar el índice de fila del botón en el que se hizo clic en el controlador de eventos RowCommand, deberá establecer manualmente la propiedad CommandArgument del botón en su sintaxis declarativa dentro de TemplateField, mediante código como:
<asp:Button runat="server" ... CommandArgument='<%# ((GridViewRow) Container).RowIndex %>'.

Resumen

Los controles GridView, DetailsView y FormView pueden incluir Botones, LinkButtons o ImageButtons. Estos botones, cuando se hace clic, provocan un postback y generan el evento ItemCommand en los controles FormView y DetailsView y el evento RowCommand en GridView. Estos controles web de datos tienen funcionalidad integrada para controlar acciones comunes relacionadas con comandos, como eliminar o editar registros. Sin embargo, también podemos usar botones que, cuando se hace clic, responden con la ejecución de nuestro propio código personalizado.

Para ello, es necesario crear un controlador de eventos para el evento ItemCommand o RowCommand. En este controlador de eventos, primero comprobamos el valor CommandName entrante para determinar en qué botón se hizo clic y, a continuación, realizar la acción personalizada adecuada. En este tutorial hemos visto cómo usar botones y ButtonFields para interrumpir todos los productos de un proveedor especificado o para aumentar o reducir el precio de un producto determinado en un 10 %.

¡Feliz programación!

Acerca del autor

Scott Mitchell, autor de siete libros de ASP/ASP.NET y fundador de 4GuysFromRolla.com, ha trabajado 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 in 24 Hours. Puede ponerse en contacto con él en mitchell@4GuysFromRolla.com. o a través de su blog, que se puede encontrar en http://ScottOnWriting.NET.