Personalizar la interfaz de edición de DataList (VB)
por Scott Mitchell
En este tutorial se creará una interfaz de edición más completa para DataList, que incluye controles DropDownList y un control CheckBox.
Introducción
Los controles de marcado y web del control DataList EditItemTemplate
definen su interfaz modificable. En todos los ejemplos de DataList editables que se han examinado hasta ahora, la interfaz editable se ha compuesto de controles web TextBox. En el tutorial anterior se ha mejorado la experiencia del usuario en tiempo de edición mediante la adición de controles de validación.
EditItemTemplate
puede ampliarse aún más para incluir controles web distintos de TextBox, como DropDownList, RadioButtonList, Calendar, etc. Como sucede con TextBox, al personalizar la interfaz de edición para incluir otros controles web, siga estos pasos:
- Agregue el control web a
EditItemTemplate
. - Use la sintaxis de enlace de datos para asignar el valor del campo de datos correspondiente a la propiedad adecuada.
- En el controlador de eventos
UpdateCommand
, acceda mediante programación al valor de control web y páselo al método de la BLL adecuado.
En este tutorial se creará una interfaz de edición más completa para DataList, que incluye controles DropDownList y un control CheckBox. En concreto, se creará un control DataList que enumere la información del producto y permite actualizar el nombre del producto, el proveedor, la categoría y el estado descatalogado (vea la figura 1).
Figura 1: La interfaz de edición incluye un control TextBox, dos controles DropDownList y un control CheckBox (Haga clic para ver la imagen a tamaño completo)
Paso 1: Representación de información del producto
Para poder crear la interfaz editable de DataList, primero es necesario crear la interfaz de solo lectura. Para empezar, abra la CustomizedUI.aspx
página desde la carpeta EditDeleteDataList
y, desde el Diseñador, agregue un control DataList a la página y establezca su propiedad ID
en Products
. En la etiqueta inteligente de DataList, cree un objeto ObjectDataSource. Asigne el nombre ProductsDataSource
a ObjectDataSource y configúrelo para que recupere datos del método GetProducts
de la clase ProductsBLL
. Al igual que con los tutoriales de DataList editables anteriores, se actualizará la información del producto editado directamente en la capa de lógica de negocios. En consecuencia, establezca las listas desplegables de las pestañas UPDATE, INSERT y DELETE en (None).
Figura 2: Establecimiento de las listas desplegables UPDATE, INSERT y DELETE en (None) (Haga clic para ver la imagen a tamaño completo)
Después de configurar ObjectDataSource, Visual Studio creará un valor ItemTemplate
predeterminado para DataList que muestra el nombre y el valor de cada uno de los campos de datos devueltos. Modifique ItemTemplate
para que la plantilla muestre el nombre del producto en un elemento <h4>
junto con el nombre de la categoría, el nombre del proveedor, el precio y el estado descatalogado. Además, agregue un botón Editar, asegurándose de que su propiedad CommandName
está establecida en Editar. El marcado declarativo para ItemTemplate
es el siguiente:
<ItemTemplate>
<h4>
<asp:Label ID="ProductNameLabel" runat="server"
Text='<%# Eval("ProductName") %>' />
</h4>
<table border="0">
<tr>
<td class="ProductPropertyLabel">Category:</td>
<td class="ProductPropertyValue">
<asp:Label ID="CategoryNameLabel" runat="server"
Text='<%# Eval("CategoryName") %>' />
</td>
<td class="ProductPropertyLabel">Supplier:</td>
<td class="ProductPropertyValue">
<asp:Label ID="SupplierNameLabel" runat="server"
Text='<%# Eval("SupplierName") %>' />
</td>
</tr>
<tr>
<td class="ProductPropertyLabel">Discontinued:</td>
<td class="ProductPropertyValue">
<asp:Label ID="DiscontinuedLabel" runat="server"
Text='<%# Eval("Discontinued") %>' />
</td>
<td class="ProductPropertyLabel">Price:</td>
<td class="ProductPropertyValue">
<asp:Label ID="UnitPriceLabel" runat="server"
Text='<%# Eval("UnitPrice", "{0:C}") %>' />
</td>
</tr>
<tr>
<td colspan="4">
<asp:Button runat="Server" ID="EditButton"
Text="Edit" CommandName="Edit" />
</td>
</tr>
</table>
<br />
</ItemTemplate>
El marcado anterior establece la información del producto mediante un título <h4> para el nombre del producto y una columna de cuatro columnas <table>
para los campos restantes. Las clases CSS ProductPropertyLabel
y ProductPropertyValue
, definidas en Styles.css
se han analizado en tutoriales anteriores. En la figura 3 se muestra el progreso cuando se ve en un explorador.
Figura 3: Se muestra el nombre, el proveedor, la categoría, el estado descatalogado y el precio de cada producto (Haga clic para ver la imagen a tamaño completo)
Paso 2: Adición de los controles web a la interfaz de edición
El primer paso para crear la interfaz de edición de DataList personalizada es agregar los controles web necesarios a EditItemTemplate
. En concreto, se necesitan un control DropDownList para la categoría, otro para el proveedor y un control CheckBox para el estado descatalogado. Como el precio del producto no se puede editar en este ejemplo, se puede seguir mostrando mediante un control web Label.
Para personalizar la interfaz de edición, haga clic en el vínculo Editar plantillas desde la etiqueta inteligente de DataList y elija la opción EditItemTemplate
en la lista desplegable. Agregue un control DropDownList a EditItemTemplate
y establezca ID
en Categories
.
Figura 4: Adición de un control DropDownList para las categorías (Haga clic para ver la imagen a tamaño completo)
A continuación, en la etiqueta inteligente de DropDownList, seleccione la opción Elegir origen de datos y cree un objeto ObjectDataSource denominado CategoriesDataSource
. Configure ObjectDataSource para usar el método GetCategories()
de la clase CategoriesBLL
(vea la figura 5). A continuación, el Asistente para configuración del origen de datos de DropDownList solicita que los campos de datos se usen para las propiedades Text
y Value
de cada instancia de ListItem
. Haga que DropDownList muestre el campo de datos CategoryName
y use CategoryID
como valor, como se muestra en la figura 6.
Figura 5: crear un nuevo ObjectDataSource denominado CategoriesDataSource
(haga clic para ver la imagen a tamaño completo)
Figura 6: Configuración de los campos de visualización y valor de DropDownList (Haga clic para ver la imagen a tamaño completo)
Repita esta serie de pasos para crear un control DropDownList para los proveedores. Establezca ID
para este control DropDownList en Suppliers
y asigne el nombre SuppliersDataSource
a ObjectDataSource.
Después de agregar los dos controles DropDownList, agregue un control CheckBox para el estado descatalogado y un control TextBox para el nombre del producto. Establezca los valores ID
de CheckBox y TextBox en Discontinued
y ProductName
, respectivamente. Agregue un control RequiredFieldValidator para asegurarse de que el usuario proporciona un valor para el nombre del producto.
Por último, agregue los botones Actualizar y Cancelar. Recuerde que para estos dos botones es fundamental que sus propiedades CommandName
estén establecidas en Actualizar y Cancelar, respectivamente.
No dude en diseñar la interfaz de edición como prefiera. Aquí se ha optado por usar el mismo diseño <table>
de cuatro columnas de la interfaz de solo lectura, como se muestra en la siguiente sintaxis declarativa y en la captura de pantalla:
<EditItemTemplate>
<h4>
<asp:Label ID="ProductNameLabel" runat="server"
Text='<%# Eval("ProductName") %>' />
</h4>
<table border="0">
<tr>
<td class="ProductPropertyLabel">Name:</td>
<td colspan="3" class="ProductPropertyValue">
<asp:TextBox runat="server" ID="ProductName" Width="90%" />
<asp:RequiredFieldValidator ID="RequiredFieldValidator1"
ControlToValidate="ProductName"
ErrorMessage="You must enter a name for the product."
runat="server">*</asp:RequiredFieldValidator>
</td>
</tr>
<tr>
<td class="ProductPropertyLabel">Category:</td>
<td class="ProductPropertyValue">
<asp:DropDownList ID="Categories" runat="server"
DataSourceID="CategoriesDataSource"
DataTextField="CategoryName" DataValueField="CategoryID" />
</td>
<td class="ProductPropertyLabel">Supplier:</td>
<td class="ProductPropertyValue">
<asp:DropDownList ID="Suppliers"
DataSourceID="SuppliersDataSource" DataTextField="CompanyName"
DataValueField="SupplierID" runat="server" />
</td>
</tr>
<tr>
<td class="ProductPropertyLabel">Discontinued:</td>
<td class="ProductPropertyValue">
<asp:CheckBox runat="server" id="Discontinued" />
</td>
<td class="ProductPropertyLabel">Price:</td>
<td class="ProductPropertyValue">
<asp:Label ID="UnitPriceLabel" runat="server"
Text='<%# Eval("UnitPrice", "{0:C}") %>' />
</td>
</tr>
<tr>
<td colspan="4">
<asp:Button runat="Server" ID="UpdateButton" CommandName="Update"
Text="Update" />
<asp:Button runat="Server" ID="CancelButton" CommandName="Cancel"
Text="Cancel" CausesValidation="False" />
</td>
</tr>
</table>
<br />
<asp:ObjectDataSource ID="CategoriesDataSource" runat="server"
OldValuesParameterFormatString="original_{0}" SelectMethod="GetCategories"
TypeName="CategoriesBLL">
</asp:ObjectDataSource>
<asp:ObjectDataSource ID="SuppliersDataSource" runat="server"
OldValuesParameterFormatString="original_{0}" SelectMethod="GetSuppliers"
TypeName="SuppliersBLL">
</asp:ObjectDataSource>
</EditItemTemplate>
Figura 7: La interfaz de edición está diseñada como la interfaz de solo lectura (Haga clic para ver la imagen a tamaño completo)
Paso 3: Creación de los controladores de eventos EditCommand y CancelCommand
Actualmente, no hay ninguna sintaxis de enlace de datos en EditItemTemplate
(excepto para UnitPriceLabel
, que se ha copiado de ItemTemplate
). Agregará la sintaxis de enlace de datos momentáneamente, pero primero se crearán los controladores de eventos para los eventos EditCommand
y CancelCommand
de DataList. Recuerde que la responsabilidad del controlador de eventos EditCommand
es representar la interfaz de edición para el control DataList cuyo botón Editar se ha pulsado, mientras que el trabajo de CancelCommand
es devolver al control DataList a su estado anterior a la edición.
Cree estos dos controladores de eventos y haga que usen el código siguiente:
Protected Sub Products_EditCommand(source As Object, e As DataListCommandEventArgs) _
Handles Products.EditCommand
' Set the DataList's EditItemIndex property to the
' index of the DataListItem that was clicked
Products.EditItemIndex = e.Item.ItemIndex
' Rebind the data to the DataList
Products.DataBind()
End Sub
Protected Sub Products_CancelCommand(source As Object, e As DataListCommandEventArgs) _
Handles Products.CancelCommand
' Set the DataList's EditItemIndex property to -1
Products.EditItemIndex = -1
' Rebind the data to the DataList
Products.DataBind()
End Sub
Después de crear estos dos controladores de eventos, al hacer clic en el botón Editar se muestra la interfaz de edición y al hacer clic en el botón Cancelar se devuelve el elemento editado a su modo de solo lectura. En la figura 8 se muestra el control DataList después de hacer clic en el botón Editar para Chef Anton's Gumbo Mix. Como todavía no se ha agregado sintaxis de enlace de datos a la interfaz de edición, el control TextBox ProductName
está en blanco, el control CheckBox Discontinued
desactivado y los primeros elementos seleccionados de los controles DropDownList Categories
y Suppliers
.
Figura 8: Al hacer clic en el botón Editar muestra la interfaz de edición (Haga clic para ver la imagen a tamaño completo)
Paso 4: Adición de la sintaxis DataBinding a la interfaz de edición
Para que la interfaz de edición muestre los valores actuales del producto, es necesario usar la sintaxis de enlace de datos para asignar los valores del campo de datos a los valores de control web adecuados. La sintaxis de enlace de datos se puede aplicar desde el Diseñador; para ello, vaya a la pantalla Editar plantillas y seleccione el vínculo Editar DataBindings de las etiquetas inteligentes de los controles web. Como alternativa, la sintaxis de enlace de datos se puede agregar directamente al marcado declarativo.
Asigne el valor del campo de datos ProductName
a la propiedad Text
del control TextBox ProductName
, los valores de campo de datos CategoryID
y SupplierID
a las propiedades SelectedValue
de los controles DropDownList Categories
y Suppliers
, y el valor de campo de datos Discontinued
a la propiedad Checked
del control CheckBox Discontinued
. Después de realizar estos cambios, ya sea desde el Diseñador o directamente mediante el marcado declarativo, vuelva a visitar la página en un explorador y haga clic en el botón Editar para Chef Anton's Gumbo Mix. Como se muestra en la figura 9, la sintaxis de enlace de datos ha agregado los valores actuales a los controles TextBox, DropDownList y CheckBox.
Figura 9: Al hacer clic en el botón Editar se muestra la interfaz de edición (Haga clic para ver la imagen a tamaño completo)
Paso 5: Guardado los cambios del usuario en el controlador de eventos UpdateCommand
Cuando el usuario edita un producto y hace clic en el botón Actualizar, se produce un postback y se desencadena el evento DataList UpdateCommand
. En el controlador de eventos, es necesario leer los valores de los controles web en EditItemTemplate
y la interfaz con la BLL para actualizar el producto en la base de datos. Como ha visto en los tutoriales anteriores, el valor ProductID
del producto actualizado es accesible desde la colección DataKeys
. Para acceder a los campos especificados por el usuario, se hace referencia mediante programación a los controles web con FindControl("controlID")
, como se muestra en el código siguiente:
Protected Sub Products_UpdateCommand(source As Object, e As DataListCommandEventArgs) _
Handles Products.UpdateCommand
If Not Page.IsValid Then
Exit Sub
End If
' Read in the ProductID from the DataKeys collection
Dim productID As Integer = Convert.ToInt32(Products.DataKeys(e.Item.ItemIndex))
' Read in the product name and price values
Dim productName As TextBox = CType(e.Item.FindControl("ProductName"), TextBox)
Dim categories As DropDownList=CType(e.Item.FindControl("Categories"), DropDownList)
Dim suppliers As DropDownList = CType(e.Item.FindControl("Suppliers"), DropDownList)
Dim discontinued As CheckBox = CType(e.Item.FindControl("Discontinued"), CheckBox)
Dim productNameValue As String = Nothing
If productName.Text.Trim().Length > 0 Then
productNameValue = productName.Text.Trim()
End If
Dim categoryIDValue As Integer = Convert.ToInt32(categories.SelectedValue)
Dim supplierIDValue As Integer = Convert.ToInt32(suppliers.SelectedValue)
Dim discontinuedValue As Boolean = discontinued.Checked
' Call the ProductsBLL's UpdateProduct method...
Dim productsAPI As New ProductsBLL()
productsAPI.UpdateProduct(productNameValue, categoryIDValue, supplierIDValue, _
discontinuedValue, productID)
' Revert the DataList back to its pre-editing state
Products.EditItemIndex = -1
Products.DataBind()
End Sub
El código comienza consultando la propiedad Page.IsValid
para asegurarse de que todos los controles de validación de la página son válidos. Si Page.IsValid
es True
, el valor ProductID
del producto editado se lee de la colección DataKeys
y se hace referencia mediante programación a los controles web de entrada de datos de EditItemTemplate
. A continuación, los valores de estos controles web se leen en variables que luego se pasan a la sobrecarga de UpdateProduct
adecuada. Después de actualizar los datos, DataList se devuelve al estado anterior a la edición.
Nota:
Se ha omitido la lógica de control de excepciones agregada en el tutorial Control de excepciones de nivel de BLL y DAL para ordenar el código y este ejemplo. Como ejercicio, agregue esta funcionalidad después de completar este tutorial.
Paso 6: Control de valores NULL en CategoryID y SupplierID
La base de datos Northwind permite valores NULL
para las columnas CategoryID
y SupplierID
de la tabla Products
. Pero la interfaz de edición no admite actualmente valores NULL
. Si intenta editar un producto que tiene un valor NULL
para sus columnas CategoryID
o SupplierID
, se obtendrá ArgumentOutOfRangeException
con un mensaje de error similar a: "Categories" tiene un SelectedValue que no es válido porque no existe en la lista de elementos. Además, actualmente no hay ninguna manera de cambiar la categoría o el valor de proveedor de un producto de un valor que no sea NULL
a NULL
.
A fin de admitir valores NULL
para los controles DropDownList de categoría y proveedor, es necesario agregar un elemento ListItem
. Se ha optado por usar (None) como valor Text
para este elemento ListItem
, pero si quiere puede cambiarlo por otro (por ejemplo, una cadena vacía). Por último, recuerde establecer AppendDataBoundItems
de DropDownList en True
; si no lo hace, las categorías y los proveedores enlazados a DropDownList sobrescribirán el valor ListItem
agregado estáticamente.
Después de realizar estos cambios, el marcado de DropDownList en DataList EditItemTemplate
debe ser similar al siguiente:
<asp:DropDownList ID="Categories" DataSourceID="CategoriesDataSource"
DataTextField="CategoryName" DataValueField="CategoryID" runat="server"
SelectedValue='<%# Eval("CategoryID") %>' AppendDataBoundItems="True">
<asp:ListItem Value=" Selected="True">(None)</asp:ListItem>
</asp:DropDownList>
...
<asp:DropDownList ID="Suppliers" DataSourceID="SuppliersDataSource"
DataTextField="CompanyName" DataValueField="SupplierID" runat="server"
SelectedValue='<%# Eval("SupplierID") %>' AppendDataBoundItems="True">
<asp:ListItem Value=" Selected="True">(None)</asp:ListItem>
</asp:DropDownList>
Nota:
Los elementos ListItem
estáticos se pueden agregar a DropDownList desde el Diseñador o directamente con la sintaxis declarativa. Al agregar un elemento DropDownList para representar un valor de base de datos NULL
, asegúrese de agregar ListItem
mediante la sintaxis declarativa. Si usa el Editor de colección ListItem
en el Diseñador, la sintaxis declarativa generada omitirá el valor Value
por completo cuando se le haya asignado una cadena en blanco, y creará marcado declarativo como: <asp:ListItem>(None)</asp:ListItem>
. Aunque esto puede parecer inofensivo, el elemento Value
que falta hace que DropDownList use el valor de la propiedad Text
en su lugar. Esto significa que, si se selecciona esta instancia de NULL
ListItem
, se intentará asignar el valor (None) al campo de datos del producto (CategoryID
o SupplierID
, en este tutorial), lo que dará lugar a una excepción. Al establecer explícitamente Value=""
, se asignará un valorNULL
al campo de datos del producto cuando se seleccione NULL
ListItem
.
Tómese un momento para ver el progreso en un explorador. Al editar un producto, tenga en cuenta que los controles DropDownList Categories
y Suppliers
tienen una opción (None) al principio.
Figura 10: Los controles DropDownList Categories
y Suppliers
incluyen una opción (None) (Haga clic para ver la imagen a tamaño completo)
Para guardar la opción (Ninguno) como valor de base de datos NULL
, es necesario volver al controlador de eventos UpdateCommand
. Cambie las variables categoryIDValue
y supplierIDValue
para que sean enteros que aceptan valores NULL y asígneles un valor distinto de Nothing
solo si el valor SelectedValue
de DropDownList no es una cadena vacía:
Dim categoryIDValue As Nullable(Of Integer) = Nothing
If Not String.IsNullOrEmpty(categories.SelectedValue) Then
categoryIDValue = Convert.ToInt32(categories.SelectedValue)
End If
Dim supplierIDValue As Nullable(Of Integer) = Nothing
If Not String.IsNullOrEmpty(suppliers.SelectedValue) Then
supplierIDValue = Convert.ToInt32(suppliers.SelectedValue)
End If
Con este cambio, se pasará un valor de Nothing
al método UpdateProduct
de la BLL si el usuario ha seleccionado la opción (None) en cualquiera de las listas desplegables, lo que corresponde a un valor de base de datos NULL
.
Resumen
En este tutorial ha visto cómo crear una interfaz de edición de DataList más compleja que incluía tres controles web de entrada diferentes, un control TextBox, dos controles DropDownList y un control CheckBox junto con controles de validación. Al crear la interfaz de edición, los pasos son los mismos independientemente de los controles web que se usen: primero se agregan los controles web a EditItemTemplate
de DataList; se usa la sintaxis de enlace de datos para asignar los valores de campo de datos correspondientes con las propiedades de control web adecuadas; y, en el controlador de eventos UpdateCommand
, se accede mediante programación a los controles web y sus propiedades adecuadas, y se pasan sus valores a la BLL.
Al crear una interfaz de edición, tanto si se compone de controles TextBox como de una colección de controles web diferentes, asegúrese de controlar correctamente los valores NULL
de base de datos. Al tener en cuenta NULL
, es fundamental que no solo muestre correctamente un valor NULL
existente en la interfaz de edición, sino que también ofrezca un medio para marcar un valor como NULL
. Para los controles DropDownList de DataList, normalmente significa agregar un valor estático ListItem
cuya propiedad Value
se establece explícitamente en una cadena vacía (Value=""
) y agregar código al controlador de eventos UpdateCommand
para determinar si se ha seleccionado NULL``ListItem
o no.
¡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 a través de mitchell@4GuysFromRolla.com. o de su blog, que se puede encontrar en http://ScottOnWriting.NET.
Agradecimientos especiales a
Esta serie de tutoriales fue revisada por muchos revisores. Los revisores principales de este tutorial fueron Dennis Patterson, David Suru y Randy Schmidt. ¿Le interesaría revisar mis próximos artículos de MSDN? Si fuera así, escríbame a mitchell@4GuysFromRolla.com.