Personalizar la interfaz de modificación de datos (VB)

por Scott Mitchell

Descargar PDF

En este tutorial, verá cómo personalizar la interfaz de un control GridView modificable, y reemplazar los controles TextBox y CheckBox estándar por controles web de entrada alternativos.

Introducción

Los controles BoundField y CheckBoxField usados por los controles GridView y DetailsView simplifican el proceso de modificación de datos debido a su capacidad de representar interfaces de solo lectura, modificable e insertables. Estas interfaces se pueden representar sin necesidad de agregar ningún código o marcado declarativo adicional. Pero las interfaces de BoundField y CheckBoxField carecen de la personalización que a menudo se necesita en escenarios reales. Para personalizar la interfaz modificable o insertable en un control GridView o DetailsView, en su lugar es necesario usar una instancia de TemplateField.

En el tutorial anterior ha visto cómo personalizar las interfaces de modificación de datos mediante la adición de controles web de validación. En este tutorial, verá cómo personalizar los controles web de recopilación de datos reales y reemplazar los controles TextBox y CheckBoxField estándar de BoundField y CheckBox Con controles web de entrada alternativos. En concreto, creará un control GridView modificable que permita actualizar el nombre, la categoría, el proveedor y el estado de un producto. Al editar una fila determinada, los campos de categoría y proveedor se representarán como controles DropDownList, que contienen el conjunto de categorías y proveedores disponibles entre los que elegir. Además, reemplazará el elemento CheckBoxField predeterminado de CheckBoxField por un control RadioButtonList que ofrece dos opciones: "Active" y "Discontinued".

The GridView's Editing Interface Includes DropDownLists and RadioButtons

Figura 1: La interfaz de edición de GridView incluye controles DropDownList y RadioButton (Haga clic para ver la imagen a tamaño completo)

Paso 1: Creación de la sobrecarga de UpdateProduct adecuada

En este tutorial, creará un control GridView modificable que permita la edición del nombre, la categoría, el proveedor y el estado de un producto. Por tanto, necesita una sobrecarga de UpdateProduct que acepte cinco parámetros de entrada estos: cuatro valores de producto más ProductID. Como las sobrecargas anteriores, esta hará lo siguiente:

  1. Recuperar la información del producto de la base de datos para el objeto ProductID especificado,
  2. Actualizar los campos ProductName, CategoryID, SupplierID y Discontinued, y
  3. Enviar la solicitud de actualización a DAL por medio del método Update() de TableAdapter.

Por motivos de brevedad, para esta sobrecarga concreta se ha omitido la comprobación de la regla de negocio que garantiza que un producto que se marque como no disponible no sea el único producto ofrecido por su proveedor. No dude en agregarla si lo prefiere o, idealmente, refactorizar la lógica en un método independiente.

En el código siguiente se muestra la nueva sobrecarga de UpdateProduct en la clase ProductsBLL:

<System.ComponentModel.DataObjectMethodAttribute(System.ComponentModel.DataObjectMethodType.Update, False)>
Public Function UpdateProduct(
    ByVal productName As String, ByVal categoryID As Nullable(Of Integer), 
    ByVal supplierID As Nullable(Of Integer), ByVal discontinued As Boolean, 
    ByVal productID As Integer)
    As Boolean
    Dim products As Northwind.ProductsDataTable = Adapter.GetProductByProductID(productID)
    If products.Count = 0 Then
        Return False
    End If
    Dim product As Northwind.ProductsRow = products(0)
    product.ProductName = productName
    If Not supplierID.HasValue Then
        product.SetSupplierIDNull()
    Else
        product.SupplierID = supplierID.Value
    End If
    If Not categoryID.HasValue Then
        product.SetCategoryIDNull()
    Else
        product.CategoryID = categoryID.Value
    End If
    product.Discontinued = discontinued
    Dim rowsAffected As Integer = Adapter.Update(product)
    Return rowsAffected = 1
End Function

Paso 2: Creación del control GridView modificable

Después de agregar la sobrecarga de UpdateProduct, ya puede crear el control GridView modificable. Abra la página CustomizedUI.aspx en la carpeta EditInsertDelete y agregue un control GridView al Diseñador. A continuación, cree una instancia de ObjectDataSource desde la etiqueta inteligente de GridView. Configure ObjectDataSource para recuperar información del producto con el método GetProducts() de la clase ProductBLL y para actualizar los datos del producto mediante la sobrecarga de UpdateProduct que acaba de crear. En las pestañas INSERT y DELETE, seleccione (Ninguno) en las listas desplegables.

Configure the ObjectDataSource to Use the UpdateProduct Overload Just Created

Figura 2: Configuración de ObjectDataSource para usar la sobrecarga de UpdateProduct que se acaba de crear (Haga clic para ver la imagen a tamaño completo)

Como ha visto en los tutoriales de modificación de datos, la sintaxis declarativa de ObjectDataSource creada por Visual Studio asigna la propiedad OldValuesParameterFormatString a original_{0}. Esto, por supuesto, no funcionará con la capa de lógica de negocios, ya que los métodos no esperan que se pase el valor ProductID original. Por tanto, como ha hecho en los tutoriales anteriores, dedique un momento a quitar esta asignación de propiedad de la sintaxis declarativa o, en su lugar, establezca el valor de esta propiedad en {0}.

Después de este cambio, el marcado declarativo de ObjectDataSource debe ser similar al siguiente:

<asp:ObjectDataSource ID="ObjectDataSource1" runat="server"
    SelectMethod="GetProducts" TypeName="ProductsBLL"
    UpdateMethod="UpdateProduct">
    <UpdateParameters>
        <asp:Parameter Name="productName" Type="String" />
        <asp:Parameter Name="categoryID" Type="Int32" />
        <asp:Parameter Name="supplierID" Type="Int32" />
        <asp:Parameter Name="discontinued" Type="Boolean" />
        <asp:Parameter Name="productID" Type="Int32" />
    </UpdateParameters>
</asp:ObjectDataSource>

Observe que la propiedad OldValuesParameterFormatString se ha quitado y que hay un elemento Parameter en la colección UpdateParameters para cada uno de los parámetros de entrada que espera la sobrecarga de UpdateProduct.

Aunque ObjectDataSource está configurado para actualizar solo un subconjunto de valores de producto, en GridView se muestran actualmente todos los campos del producto. Dedique un momento a editar GridView para que:

  • Solo incluya las instancias de BoundField ProductName, SupplierName y CategoryName, y el control CheckBoxField Discontinued
  • Los campos CategoryName y SupplierName aparezcan antes que (a la izquierda) el control CheckBoxField Discontinued
  • La HeaderText de los controles BoundField CategoryName y SupplierName se establezca en "Category" y "Supplier", respectivamente
  • La compatibilidad con la edición está habilitada (active la casilla Habilitar edición en la etiqueta inteligente de GridView)

Después de estos cambios, el Diseñador tendrá un aspecto similar al de la figura 3, con la sintaxis declarativa de GridView que se muestra a continuación.

Remove the Unneeded Fields from the GridView

Figura 3: Eliminación de los campos innecesarios de GridView (Haga clic para ver la imagen a tamaño completo)

<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False"
    DataKeyNames="ProductID" DataSourceID="ObjectDataSource1">
    <Columns>
        <asp:BoundField DataField="ProductName"
           HeaderText="ProductName" SortExpression="ProductName" />
        <asp:BoundField DataField="CategoryName" HeaderText="Category"
           ReadOnly="True"
           SortExpression="CategoryName" />
        <asp:BoundField DataField="SupplierName" HeaderText="Supplier"
           ReadOnly="True"
           SortExpression="SupplierName" />
        <asp:CheckBoxField DataField="Discontinued"
           HeaderText="Discontinued" SortExpression="Discontinued" />
    </Columns>
</asp:GridView>

En este momento, el comportamiento de solo lectura de GridView está completo. Al ver los datos, cada producto se representa como una fila en el control GridView, y muestra el nombre del producto, la categoría, el proveedor y el estado interrumpido.

The GridView's Read-Only Interface is Complete

Figura 4: La interfaz de solo lectura de GridView está completa (Haga clic para ver la imagen a tamaño completo)

Nota:

Como se describe en el tutorial Introducción a la inserción, actualización y eliminación de datos, es fundamental que el estado de visualización de GridView esté habilitado (el comportamiento predeterminado). Si establece la propiedad EnableViewStatede GridView en false, corre el riesgo de que los usuarios simultáneos eliminen o editen registros accidentalmente.

Paso 3: Uso de una lista desplegable para las interfaces de edición de categoría y proveedor

Recuerde que el objeto ProductsRow contiene las propiedades CategoryID, CategoryName, SupplierID y SupplierName, que proporcionan los valores reales de identificador de clave externa en la tabla de base de datos Products y los valores Name correspondientes de las tablas Categories y Suppliers. CategoryID y SupplierID de ProductRow se pueden leer desde y escribir en ellos, mientras que las propiedades CategoryName y SupplierName están marcadas como de solo lectura.

Debido al estado de solo lectura de las propiedades CategoryName y SupplierName, en los controles BoundField correspondientes se ha establecido la propiedad ReadOnly enTrue, lo que impide que estos valores se modifiquen al editar una fila. Aunque se puede establecer la propiedad ReadOnly en False, y representar los controles BoundField CategoryName y SupplierName como controles TextBox durante la edición, este enfoque iniciaría una excepción cuando el usuario intente actualizar el producto, ya que no hay ninguna sobrecarga de UpdateProduct que tome entradas CategoryName y SupplierName. De hecho, no querrá crear esta sobrecarga por dos motivos:

  • La tabla Products no tiene campos SupplierName ni CategoryName, pero sí SupplierID y CategoryID. Por tanto, quiere que al método se le pasen estos valores de identificador concretos, no sus valores de las tablas de búsqueda.
  • Exigir al usuario que escriba el nombre del proveedor o categoría no es lo ideal, ya que requiere que el usuario conozca las categorías y proveedores disponibles y su ortografía correcta.

Los campos de proveedor y categoría deben mostrar los nombres de categoría y proveedores cuando están en modo de solo lectura (como ahora) y una lista desplegable de opciones aplicables cuando se editen. Con una lista desplegable, el usuario final puede ver rápidamente qué categorías y proveedores están disponibles para elegir y puede realizar su selección más fácilmente.

Para proporcionar este comportamiento, es necesario convertir las instancias de BoundField SupplierName y CategoryName en elementos TemplateField en los que ItemTemplate emita los valores SupplierName y CategoryName, y EditItemTemplate use un control DropDownList para enumerar las categorías y proveedores disponibles.

Adición de los controles DropDownList Categories y Suppliers

Para empezar, convierta las instancias de BoundField SupplierName y CategoryName en elementos TemplateField; para ello, haga clic en el vínculo Editar columnas de la etiqueta inteligente de GridView; seleccione BoundField en la lista de la parte inferior izquierda y haga clic en el vínculo "Convertir este campo en TemplateField". El proceso de conversión creará una instancia de TemplateField con ItemTemplate y EditItemTemplate, como se muestra en la sintaxis declarativa siguiente:

<asp:TemplateField HeaderText="Category" SortExpression="CategoryName">
    <EditItemTemplate>
        <asp:Label ID="Label1" runat="server"
          Text='<%# Eval("CategoryName") %>'></asp:Label>
    </EditItemTemplate>
    <ItemTemplate>
        <asp:Label ID="Label1" runat="server"
          Text='<%# Bind("CategoryName") %>'></asp:Label>
    </ItemTemplate>
</asp:TemplateField>

Como BoundField se ha marcado como de solo lectura, ItemTemplate y EditItemTemplate contienen un control web de etiqueta cuya propiedad Text está enlazada al campo de datos aplicable (CategoryName, en la sintaxis anterior). Es necesario modificar EditItemTemplate y reemplazar el control web Label por un control DropDownList.

Como ha visto en los tutoriales anteriores, la plantilla se puede editar desde el Diseñador o directamente desde la sintaxis declarativa. Para editarla desde el Diseñador, haga clic en el vínculo Editar plantillas de la etiqueta inteligente de GridView y elija trabajar con el elemento EditItemTemplate del campo Category. Quite el control web Label y reemplácelo por un control DropDownList, y establezca la propiedad ID de DropDownList en Categories.

Remove the TexBox and Add a DropDownList to the EditItemTemplate

Figura 5: Eliminación de TexBox y adición de un control DropDownList a EditItemTemplate (Haga clic para ver la imagen a tamaño completo)

A continuación, es necesario rellenar DropDownList con las categorías disponibles. Haga clic en el vínculo Elegir origen de datos de la etiqueta inteligente de DropDownList y opte por crear un objeto ObjectDataSource denominado CategoriesDataSource.

Create a New ObjectDataSource Control Named CategoriesDataSource

Figura 6: Creación de una instancia de ObjectDataSource con el nombre CategoriesDataSource (Haga clic para ver la imagen a tamaño completo)

Para que esta instancia de ObjectDataSource devuelva todas las categorías, se debe enlazar al método GetCategories() de la clase CategoriesBLL.

Bind the ObjectDataSource to the CategoriesBLL's GetCategories() Method

Figura 7: Enlace de ObjectDataSource al método GetCategories() de CategoriesBLL (Haga clic para ver la imagen a tamaño completo)

Por último, configure lo valores de DropDownList de modo que el campo CategoryName se muestre en cada ListItem de DropDownList con el campo CategoryID como valor.

Have the CategoryName Field Displayed and the CategoryID Used as the Value

Figura 8: Representación del campo CategoryName y uso de CategoryID como valor (Haga clic para ver la imagen a tamaño completo)

Después de realizar estos cambios, el marcado declarativo para EditItemTemplate la instancia de TemplateField CategoryName incluirá DropDownList y ObjectDataSource:

<asp:TemplateField HeaderText="Category" SortExpression="CategoryName">
    <EditItemTemplate>
        <asp:DropDownList ID="Categories" runat="server"
          DataSourceID="CategoriesDataSource"
          DataTextField="CategoryName" DataValueField="CategoryID">
        </asp:DropDownList>
        <asp:ObjectDataSource ID="CategoriesDataSource" runat="server"
            OldValuesParameterFormatString="original_{0}"
            SelectMethod="GetCategories" TypeName="CategoriesBLL">
        </asp:ObjectDataSource>
    </EditItemTemplate>
    <ItemTemplate>
        <asp:Label ID="Label1" runat="server"
          Text='<%# Bind("CategoryName") %>'></asp:Label>
    </ItemTemplate>
</asp:TemplateField>

Nota:

El control DropDownList de EditItemTemplate debe tener habilitado su estado de visualización. En breve agregará sintaxis de enlace de datos a la sintaxis declarativa de DropDownList y los comandos de enlace de datos como Eval() y Bind() solo se pueden mostrar en los controles cuyo estado de visualización está habilitado.

Repita estos pasos para agregar un control DropDownList denominado Suppliers al elemento EditItemTemplate de la instancia de TemplateField SupplierName. Esto implicará agregar un control DropDownList a EditItemTemplate y crear otra instancia de ObjectDataSource. Pero la instancia de ObjectDataSource del control DropDownList Suppliers se debe configurar para invocar el método GetSuppliers() de la clase SuppliersBLL. Además, configure el control DropDownList Suppliers para mostrar el campo CompanyName y usar el campo SupplierID como valor deListItem.

Después de agregar los controles DropDownList a las dos instancias de EditItemTemplate, abra la página en un explorador y haga clic en el botón Editar para el producto Chef Anton's Cajun Seasoning. Como se muestra en la figura 9, las columnas de categoría y proveedor del producto se representan como listas desplegables que contienen las categorías y proveedores disponibles entre las que elegir. Pero observe que los primeros elementos de las dos listas desplegables se seleccionan de forma predeterminada (Beverages para la categoría y Exotic Liquids como proveedor), aunque Chef Anton's Cajun Seasoning sea un producto Condiment suministrado por New Orleans Cajun Delights.

The First Item in the Drop-Down Lists is Selected by Default

Figura 9: El primer elemento de las listas desplegables está seleccionado de forma predeterminada (Haga clic para ver la imagen a tamaño completo)

Además, si hace clic en Actualizar, verá que los valores CategoryID y SupplierID del producto se establecen en NULL. Estos dos comportamientos no deseados se deben a que los controles DropDownList de las instancias de EditItemTemplate no están enlazados a ningún campo de datos de los datos de producto subyacentes.

Enlace de los controles DropDownList a los campos de datos CategoryID ySupplierID

Para que las listas desplegables de proveedor y categoría del producto editado se establezcan en los valores adecuados y para que estos valores se envíen de vuelta al método UpdateProduct de BLL al hacer clic en Actualizar, es necesario enlazar las propiedades SelectedValue de los controles DropDownList a los campos de datos CategoryID y SupplierID mediante el enlace de datos bidireccional. Para lograrlo con el control DropDownList Categories, puede agregar SelectedValue='<%# Bind("CategoryID") %>' directamente a la sintaxis declarativa.

Como alternativa, puede establecer los enlaces de datos de DropDownList si edita la plantilla desde el Diseñador y hace clic en el vínculo Editar DataBindings desde la etiqueta inteligente de DropDownList. A continuación, indique que la propiedad SelectedValue se debe enlazar al campo CategoryID mediante el enlace de datos bidireccional (vea la figura 10). Repita el proceso declarativo o del Diseñador para enlazar el campo de datos SupplierID al control DropDownList Suppliers.

Bind the CategoryID to the DropDownList's SelectedValue Property Using Two-Way Databinding

Figura 10: Enlace de CategoryID a la propiedad SelectedValue de DropDownList mediante el enlace de datos bidireccional (Haga clic para ver la imagen a tamaño completo)

Una vez que se hayan aplicado los enlaces a las propiedades SelectedValue de los dos controles DropDownList, columnas de categoría y proveedor del producto editado tendrán como valor predeterminado los valores del producto actual. Al hacer clic en Actualizar, los valores CategoryID y SupplierID del elemento de lista desplegable seleccionado se pasarán al método UpdateProduct. En la figura 11 se muestra el tutorial después de agregar las instrucciones de enlace de datos; observe cómo los elementos de lista desplegable seleccionados para Chef Anton's Cajun Seasoning son correctamente Condiment y New Orleans Cajun Delights.

The Edited Product's Current Category and Supplier Values are Selected by Default

Figura 11: Los valores actuales de categoría y proveedor del producto editado están seleccionados de forma predeterminada (Haga clic para ver la imagen a tamaño completo)

Control de valores NULL

Las columnas CategoryID y SupplierID de la tabla Products pueden ser NULL, pero los controles DropDownList de las instancias de EditItemTemplate no incluyen un elemento de lista para representar un valor NULL. Esto tiene dos consecuencias:

  • El usuario no puede usar la interfaz para cambiar la categoría o el proveedor de un producto de un valor que no es NULL a uno que sea NULL
  • Si un producto tiene NULLCategoryID o SupplierID, al hacer clic en el botón Editar se producirá una excepción. Esto se debe a que el valor NULL devuelto por CategoryID (o SupplierID) en la instrucción Bind() no se asigna a un valor del control DropDownList (el control DropDownList inicia una excepción cuando su propiedad SelectedValue está establecida en un valor que no se incluye en su colección de elementos de lista).

Para admitir valores NULLCategoryID y SupplierID, es necesario agregar otra instancia de ListItem a cada control DropDownList para representar el valor NULL. En el tutorial Filtrado de maestros y detalles con una lista desplegable, ha visto cómo agregar un elemento ListItem adicional a un control DropDownList con enlace de datos, lo que implicaba establecer la propiedad AppendDataBoundItems de DropDownList en True y agregar manualmente el elemento ListItem adicional. Pero en ese tutorial anterior se ha agregado un elemento ListItem con una instancia Value de -1. Pero la lógica de enlace de datos en ASP.NET convertirá automáticamente una cadena en blanco en un valor NULL y viceversa. Por tanto, para este tutorial querrá que ValueListItem sea una cadena vacía.

Para empezar, establezca la propiedad AppendDataBoundItems de los controles DropDownList en True. A continuación, agregue NULLListItem mediante la adición del elemento <asp:ListItem> siguiente a cada control DropDownList para que el marcado declarativo tenga el siguiente aspecto:

<asp:DropDownList ID="Categories" runat="server"
    DataSourceID="CategoriesDataSource" DataTextField="CategoryName"
    DataValueField="CategoryID" SelectedValue='<%# Bind("CategoryID") %>'
    AppendDataBoundItems="True">
    <asp:ListItem Value="">(None)</asp:ListItem>
</asp:DropDownList>

Para esta instancia de ListItem se usa "(None)" como valor de texto, pero si quiere puede cambiarlo para que también sea una cadena en blanco.

Nota:

Como ha visto en el tutorial Filtrado de maestros y detalles con una lista desplegable, puede agregar instancias de ListItem a un control DropDownList desde el Diseñador si hace clic en la propiedad Items de DropDownList en la ventana Propiedades (que mostrará el Editor de colecciones ListItem). Pero en este tutorial asegúrese de agregar NULLListItem mediante la sintaxis declarativa. Si usa el Editor de colecciones ListItem, la sintaxis declarativa generada omitirá por completo el valor Value cuando se le asigne una cadena en blanco, y creará marcado declarativo como: <asp:ListItem>(None)</asp:ListItem>. Aunque esto puede parecer inofensivo, el valor que falta hace que DropDownList use el valor de la propiedad Text en su lugar. Esto significa que, si se selecciona NULLListItem, se intentará asignar el valor "(None)" a CategoryID, lo que dará lugar a una excepción. Al establecer Value=""de forma explícita, se asignará un valor NULL a CategoryID cuando se seleccione NULLListItem.

Repita estos pasos para la lista desplegable Suppliers.

Con esta instancia de ListItem adicional, la interfaz de edición ahora puede asignar valores NULL a los campos CategoryID y SupplierID de un producto, como se muestra en la figura 12.

Choose (None) to Assign a NULL Value for a Product's Category or Supplier

Figura 12: Elección de (None) para asignar un valor NULL para la categoría o el proveedor de un producto (Haga clic para ver la imagen a tamaño completo )

Paso 4: Uso de controles RadioButton para el estado interrumpido

Actualmente, el campo de datos Discontinued de los productos se expresa mediante un control CheckBoxField, que representa una casilla deshabilitada para las filas de solo lectura y una casilla habilitada para la fila que se editan. Aunque esta interfaz de usuario suele ser adecuada, se puede personalizarla si es necesario mediante una instancia de TemplateField. En este tutorial, se cambiará CheckBoxField por una instancia de TemplateField que usa un control RadioButtonList con dos opciones "Active" y "Discontinued" desde las que el usuario puede especificar el valor Discontinued del producto.

Para empezar, convierta la instancia de CheckBoxField Discontinued en un control TemplateField, que creará una instancia de TemplateField con ItemTemplate y EditItemTemplate. Las dos plantillas incluyen un control CheckBox con su propiedad Checked enlazada al campo de datos Discontinued; la única diferencia entre las dos es que la propiedad Enabled del control CheckBox de ItemTemplate está establecida en False.

Reemplace CheckBox en ItemTemplate y EditItemTemplate por un control RadioButtonList, y establezca las propiedades IDde RadioButtonList en DiscontinuedChoice. A continuación, indique que los controles RadioButtonList deben contener dos botones de radio, uno con la etiqueta "Active" y un valor de "False",y otro con la etiqueta "Discontinued" y un valor de "True". Para ello, puede escribir los elementos <asp:ListItem> directamente mediante la sintaxis declarativa o usar el Editor de colecciones ListItem desde el Diseñador. En la figura 13 se muestra el Editor de colecciones ListItem después de especificar las dos opciones de botón de radio.

Add Active and Discontinued Options to the RadioButtonList

Figura 13: Adición de las opciones Active y Discontinued a RadioButtonList (Haga clic para ver la imagen a tamaño completo)

Como el control RadioButtonList de ItemTemplate no debe ser editable, establezca su propiedad Enabled en False y deje la propiedad Enabled en True (el valor predeterminado) para RadioButtonList en EditItemTemplate. Esto hará que los botones de radio de la fila no editada sean de solo lectura, pero permitirá al usuario cambiar los valores de RadioButton de la fila editada.

Todavía es necesario asignar las propiedades SelectedValue de los controles RadioButtonList para que el botón de radio adecuado se seleccione en función del campo de datos Discontinued del producto. Como sucede con los controles DropDownList que se han examinado antes en este tutorial, esta sintaxis de enlace de datos se puede agregar directamente al marcado declarativo o desde el vínculo Editar DataBindings en las etiquetas inteligentes de los controles RadioButtonList.

Después de agregar los dos controles RadioButtonList y configurarlos, el marcado declarativo de la instancia de TemplateField Discontinued debe ser similar al siguiente:

<asp:TemplateField HeaderText="Discontinued" SortExpression="Discontinued">
    <ItemTemplate>
        <asp:RadioButtonList ID="DiscontinuedChoice" runat="server"
          Enabled="False" SelectedValue='<%# Bind("Discontinued") %>'>
            <asp:ListItem Value="False">Active</asp:ListItem>
            <asp:ListItem Value="True">Discontinued</asp:ListItem>
        </asp:RadioButtonList>
    </ItemTemplate>
    <EditItemTemplate>
        <asp:RadioButtonList ID="DiscontinuedChoice" runat="server"
            SelectedValue='<%# Bind("Discontinued") %>'>
            <asp:ListItem Value="False">Active</asp:ListItem>
            <asp:ListItem Value="True">Discontinued</asp:ListItem>
        </asp:RadioButtonList>
    </EditItemTemplate>
</asp:TemplateField>

Con estos cambios, la columna Discontinued se ha transformado de una lista de casillas a una lista de pares de botones de radio (vea la figura 14). Al editar un producto, se selecciona el botón de radio adecuado y se puede actualizar el estado de interrupción del producto si se selecciona el otro botón de radio y se hace clic en Actualizar.

The Discontinued CheckBoxes Have Been Replaced by Radio Button Pairs

Figura 14: Las casillas Discontinued se han reemplazado por pares de botón de radio (Haga clic para ver la imagen a tamaño completo)

Nota:

Como la columna Discontinued de la base de datos Products no puede tener valores NULL, no es necesario preocuparse de capturar información de NULL en la interfaz. Pero si la columna Discontinued puede contener valores NULL, podría querer agregar un tercer botón de radio a la lista con Value establecido en una cadena vacía (Value=""), al igual que con los controles DropDownList de categoría y proveedor.

Resumen

Aunque BoundField y CheckBoxField representan automáticamente interfaces de edición e inserción de solo lectura, carecen de la capacidad de personalización. Pero a menudo es necesario personalizar la interfaz de edición o inserción, posiblemente con la adición de controles de validación (como en el tutorial anterior), o bien personalizar la interfaz de usuario de recopilación de datos (como en este tutorial). La personalización de la interfaz con un control TemplateField se puede resumir en los pasos siguientes:

  1. Agregar una instancia de TemplateField o convertir un control BoundField o CheckBoxField existente en TemplateField
  2. Aumentar la interfaz según sea necesario
  3. Enlazar los campos de datos adecuados a los controles web recién agregados mediante el enlace de datos bidireccional

Además de usar los controles web integrados de ASP.NET, también puede personalizar las plantillas de TemplateField con controles de servidor compilados y personalizados, y controles de usuario.

¡Feliz programación!

Acerca del autor

Scott Mitchell, autor de siete libros de ASP/ASP.NET y fundador de 4GuysFromRolla.com, trabaja 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 en su blog, que se puede encontrar en http://ScottOnWriting.NET.