Compartir a través de


Personalizar la interfaz de edición de DataList (C#)

por Scott Mitchell

Descargar PDF

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:

  1. Agregue el control web a EditItemTemplate.
  2. Use la sintaxis de enlace de datos para asignar el valor del campo de datos correspondiente a la propiedad adecuada.
  3. 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).

La interfaz de edición incluye un cuadro de texto, dos listas desplegables y una casilla

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).

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.

Se muestra el nombre, el proveedor, la categoría, el estado descatalogado y el precio de cada producto

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.

Agregar un DropDownList para las categorías

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.

Creación de ObjectDataSource denominado CategoriesDataSource

Figura 5: crear un nuevo ObjectDataSource denominado CategoriesDataSource (haga clic para ver la imagen a tamaño completo)

Configurar los campos de visualización y valor de DropDownList

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" DataTextField="CompanyName"
                    DataSourceID="SuppliersDataSource"
                    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>

La interfaz de edición está diseñada como la interfaz de solo lectura

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 void Products_EditCommand(object source, DataListCommandEventArgs e)
{
    // Set the DataList's EditItemIndex property and rebind the data
    Products.EditItemIndex = e.Item.ItemIndex;
    Products.DataBind();
}
protected void Products_CancelCommand(object source, DataListCommandEventArgs e)
{
    // Return to DataList to its pre-editing state
    Products.EditItemIndex = -1;
    Products.DataBind();
}

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.

Captura de pantalla que muestra DataList EditItemTemplate después de agregar los controladores de eventos EditCommand y CancelCommand y se ha seleccionado el botón Editar.

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 SelectedValuede 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.

Captura de pantalla que muestra DataList EditItemTemplate después de agregar la sintaxis DataBinding y se ha seleccionado el botón Editar.

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 void Products_UpdateCommand(object source, DataListCommandEventArgs e)
{
    // Make sure the page is valid...
    if (!Page.IsValid)
        return;
    // Read in the ProductID from the DataKeys collection
    int productID = Convert.ToInt32(Products.DataKeys[e.Item.ItemIndex]);
    // Read in the product name and price values
    TextBox productName = (TextBox)e.Item.FindControl("ProductName");
    DropDownList categories = (DropDownList)e.Item.FindControl("Categories");
    DropDownList suppliers = (DropDownList)e.Item.FindControl("Suppliers");
    CheckBox discontinued = (CheckBox)e.Item.FindControl("Discontinued");
    string productNameValue = null;
    if (productName.Text.Trim().Length > 0)
        productNameValue = productName.Text.Trim();
    int categoryIDValue = Convert.ToInt32(categories.SelectedValue);
    int supplierIDValue = Convert.ToInt32(suppliers.SelectedValue);
    bool discontinuedValue = discontinued.Checked;
    // Call the ProductsBLL's UpdateProduct method...
    ProductsBLL productsAPI = new ProductsBLL();
    productsAPI.UpdateProduct(productNameValue, categoryIDValue, supplierIDValue,
                              discontinuedValue, productID);
    // Revert the DataList back to its pre-editing state
    Products.EditItemIndex = -1;
    Products.DataBind();
}

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.

Las categorías y proveedores de DropDownLists incluyen una opción (None)

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:

int? categoryIDValue = null;
if (!string.IsNullOrEmpty(categories.SelectedValue))
    categoryIDValue = Convert.ToInt32(categories.SelectedValue);
int? supplierIDValue = null;
if (!string.IsNullOrEmpty(suppliers.SelectedValue))
    supplierIDValue = Convert.ToInt32(suppliers.SelectedValue);

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 es así, escríbame a mitchell@4GuysFromRolla.com.