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

por Scott Mitchell

Descargar PDF

En este tutorial crearemos una interfaz de edición más completa para DataList, una que incluye DropDownLists y un CheckBox.

Introducción

Los controles de marcado y web de DataList EditItemTemplate definen su interfaz editable. En todos los ejemplos de DataList editables que hemos 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 DropDownLists, RadioButtonLists, Calendars, etc. Al igual que con TextBoxes, 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 BLL adecuado.

En este tutorial crearemos una interfaz de edición más completa para DataList, una que incluye DropDownLists y un CheckBox. En concreto, crearemos una DataList que liste la información del producto y permitirá actualizar el nombre del producto, el proveedor, la categoría y el estado descontinuado (consulte la figura 1).

The Editing Interface Includes a TextBox, Two DropDownLists, and a CheckBox

Figura 1: La interfaz de edición incluye un TextBox, dos DropDownLists y un CheckBox (Haga clic para ver la imagen de tamaño completo)

Paso 1: Mostrar 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 DataList a la página y establezca su propiedad ID en Products. En la etiqueta inteligente DataList, cree un objeto ObjectDataSource. Asigne al nuevo ObjectDataSource ProductsDataSource y configúrelo para que recupere datos del método ProductsBLL de la clase GetProducts. Al igual que con los tutoriales de DataList editables anteriores, actualizaremos la información del producto editado directamente a la capa de lógica de negocios. En consecuencia, establezca las listas desplegables en las pestañas UPDATE, INSERT y DELETE en (Ninguno).

Set the UPDATE, INSERT, and DELETE Tabs Drop-Down Lists to (None)

Figura 2: Establecer las listas desplegables UPDATE, INSERT y DELETE en (Ninguno) (Haga clic para ver la imagen de tamaño completo)

Después de configurar ObjectDataSource, Visual Studio creará un valor predeterminado ItemTemplate 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 descontinuado. Además, agregue un botón Editar, asegurándose de que su propiedad CommandName está establecida en Editar. El marcado declarativo para mi siguiente ItemTemplate:

<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 encabezado<h4> para el nombre del producto y una columna de cuatro columnas <table> para los campos restantes. Las clases CSSProductPropertyLabel y ProductPropertyValue, definidas en Styles.css, se han analizado en tutoriales anteriores. En la figura 3 se muestra el progreso cuando se ve a través de un explorador.

The Name, Supplier, Category, Discontinued Status, and Price of Each Product is Displayed

Figura 3: Se muestra el nombre, el proveedor, la categoría, el estado descontinuado y el precio de cada producto (Haga clic para ver la imagen de tamaño completo)

Paso 2: Agregar 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, necesitamos un DropDownList para la categoría, otro para el proveedor y un CheckBox para el estado descontinuado. Puesto que el precio del producto no se puede editar en este ejemplo, podemos seguir mostrándolo mediante un control Web etiqueta.

Para personalizar la interfaz de edición, haga clic en el vínculo Editar plantillas desde la etiqueta inteligente DataList y elija la opción EditItemTemplate en la lista desplegable. Agregue un DropDownList a EditItemTemplate y establezca su ID en Categories.

Add a DropDownList for the Categories

Figura 4: Agregar un DropDownList para las categorías (Haga clic para ver la imagen de tamaño completo)

A continuación, en la etiqueta inteligente DropDownList, seleccione la opción Elegir origen de datos y cree un objeto ObjectDataSource denominado CategoriesDataSource. Configure este ObjectDataSource para usar el método GetCategories() de la clase s 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 cada propiedades ListItem s Text y Value. Haga que DropDownList muestre el campo de datos CategoryName y use CategoryID como valor, como se muestra en la figura 6.

Create a New ObjectDataSource Named CategoriesDataSource

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

Configure the DropDownList s Display and Value Fields

Figura 6: Configurar los campos de visualización y valor de DropDownList (Haga clic para ver la imagen de tamaño completo)

Repita esta serie de pasos para crear un DropDownList para los proveedores. Establezca para ID este DropDownList en Suppliers y asigne un nombre a ObjectDataSource SuppliersDataSource.

Después de agregar los dos DropDownLists, agregue un CheckBox para el estado discontinuado y un TextBox para el nombre del producto. Establezca los ID s de CheckBox y TextBox en Discontinued y ProductName, respectivamente. Agregue un 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 imperativo que sus propiedades CommandName estén establecidas en Actualizar y Cancelar, respectivamente.

No dude en diseñar la interfaz de edición, pero le gusta. He optado por usar el mismo diseño <table> de cuatro columnas desde la interfaz de solo lectura, como se muestra en la siguiente sintaxis declarativa y 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>

The Editing Interface is Laid Out like the Read-Only Interface

Figura 7: La interfaz de edición está diseñada como la interfaz de solo lectura (Haga clic para ver la imagen de tamaño completo)

Paso 3: Crear los controladores de eventos EditCommand y CancelCommand

Actualmente, no hay ninguna sintaxis de enlace de datos en EditItemTemplate (excepto paraUnitPriceLabel, que se copió en el texto textual de ItemTemplate). Agregaremos la sintaxis de enlace de datos momentáneamente, pero primero vamos a crear 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 elemento DataList cuyo botón Editar se hizo clic, mientras que los trabajos CancelCommand de s es devolver DataList a su estado de edición previa.

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();
}

Con estos dos controladores de eventos en su lugar, 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 la DataList después de hacer clic en el botón Editar para Chef Anton s Gumbo Mix. Puesto que todavía hemos agregado cualquier sintaxis de enlace de datos a la interfaz de edición, el TextBox ProductName está en blanco, la CheckBox Discontinued desactivada y los primeros elementos seleccionados de la Categories y Suppliers DropDownLists.

Screenshot showing the DataList EditItemTemplate after the EditCommand and CancelCommand event handlers have been added and the Edit button has been selected.

Figura 8: Hacer clic en el botón Editar muestra la interfaz de edición (Haga clic para ver la imagen de tamaño completo)

Paso 4: Agregar 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 a través del Diseñador; para ello, vaya a la pantalla Editar plantillas y seleccione el vínculo Editar DataBindings de las etiquetas inteligentes de 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 ProductName TextBox s Text, los valores del campo de datos CategoryID y SupplierID a las propiedades Categories y Suppliers DropDownLists SelectedValue y el valor del campo de datos Discontinued a la propiedad Discontinued CheckBox s Checked. Después de realizar estos cambios, ya sea a través del Diseñador o directamente a través del marcado declarativo, vuelva a visitar la página a través de 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 TextBox, DropDownLists y CheckBox.

Screenshot showing the DataList EditItemTemplate after the DataBinding syntax has been added and the Edit button has been selected.

Figura 9: Hacer clic en el botón Editar muestra la interfaz de edición (Haga clic para ver la imagen de tamaño completo)

Paso 5: Guardar 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 una devolución de datos y se desencadena el evento DataList UpdateCommand. En el controlador de eventos, es necesario leer los valores de los controles web en y la interfaz EditItemTemplate con el BLL para actualizar el producto en la base de datos. Como hemos visto en los tutoriales anteriores, el ProductID del producto actualizado es accesible a través de la colección DataKeys. Para acceder a los campos especificados por el usuario, se hace referencia mediante programación a los controles Web mediante 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 adecuada UpdateProduct. Después de actualizar los datos, DataList se devuelve a su estado de edición previa.

Nota:

He omitido la lógica de control de excepciones agregada en el tutorial Control de excepciones de nivel BLL y DAL para ordenar el código y este ejemplo centrado. Como ejercicio, agregue esta funcionalidad después de completar este tutorial.

Paso 6: Control de valores CategoryID y SupplierID NULL

La base de datos Northwind permite valores NULL para las Products tabla s CategoryID y SupplierID columnas. Sin embargo, nuestra interfaz de edición no admite actualmente valores NULL. Si intentamos editar un producto que tiene un valor NULL para sus columnas CategoryID o SupplierID, obtendremos 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 de NULL a un NULL.

Para admitir valores NULL para la categoría y el proveedor DropDownLists, es necesario agregar un elemento adicional ListItem. He elegido usar (None) como valor Text para este ListItem, pero puede cambiarlo a otra cosa (por ejemplo, una cadena vacía) si quiere. Por último, recuerde establecer DropDownLists AppendDataBoundItems en True; si olvida hacerlo, las categorías y los proveedores enlazados a DropDownList sobrescribirán el agregado estáticamente ListItem.

Después de realizar estos cambios, el marcado DropDownLists de DataList s 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 estáticos ListItem se pueden agregar a DropDownList a través del Diseñador o directamente a través de 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 recopilación ListItem en el Diseñador, la sintaxis declarativa generada omitirá la configuración Value por completo cuando se le haya asignado una cadena en blanco, creando marcado declarativo como: <asp:ListItem>(None)</asp:ListItem>. Aunque esto puede parecer inofensivo, el Value que falta hace que DropDownList use el valor de la propiedad Text en su lugar. Esto significa que, si se selecciona esto NULLListItem, se intentará asignar el valor (Ninguno) 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 NULLListItem se seleccione.

Tómese un momento para ver nuestro progreso a través de un explorador. Al editar un producto, tenga en cuenta que los elementos Categories y Suppliers DropDownLists tienen una opción (None) al principio de DropDownList.

The Categories and Suppliers DropDownLists include a (None) Option

Figura 10: Los DropDownLists Categories y Suppliers incluyen una opción (None) (Haga clic para ver la imagen de 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 DropDownList s SelectedValue 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 BLL UpdateProduct si el usuario ha seleccionado la opción (Ninguno) en cualquiera de las listas desplegables, lo que corresponde a un valor NULL de base de datos.

Resumen

En este tutorial vimos cómo crear una interfaz de edición de DataList más compleja que incluía tres controles web de entrada diferentes un TextBox, dos DropDownLists y un CheckBox junto con controles de validación. Al compilar la interfaz de edición, los pasos son los mismos independientemente de los controles web que se usen: empiece agregando los controles web a DataList s EditItemTemplate; use 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, acceda mediante programación a los controles web y sus propiedades adecuadas, pasar sus valores al BLL.

Al crear una interfaz de edición, tanto si se compone de TextBoxes como de una colección de controles web diferentes, asegúrese de controlar correctamente los valores de la base de datos NULL. Al tener en cuenta NULL s, es imperativo que no solo muestre correctamente un valor existente NULL en la interfaz de edición, sino también que ofrezca un medio para marcar un valor como NULL. Para DropDownLists en DataLists, normalmente significa agregar una propiedad estática ListItem cuya propiedad Value se establece explícitamente en una cadena vacía (Value="") y agregar un poco de código al UpdateCommand controlador de eventos para determinar si se seleccionó o no NULL``ListItem.

¡Feliz programación!

Acerca del autor

Scott Mitchell, autor de siete libros de ASP/ASP.NET y fundador de 4GuysFromRolla.com, ha estado trabajando con tecnologías web de Microsoft desde 1998. Scott trabaja como consultor independiente, entrenador y escritor. Su último libro es Sams Teach Yourself ASP.NET 2.0 in 24 Hours. Puede ponerse en contacto con él vía mitchell@4GuysFromRolla.com. o a través de su blog, que se puede encontrar en http://ScottOnWriting.NET.

Agradecimientos especiales a

Esta serie de tutoriales fue revisada por muchos revisores de gran ayuda. Los revisores principales de este tutorial fueron Dennis Patterson, David Suru y Randy Schmidt. ¿Le interesa revisar mis próximos artículos de MSDN? Si es así, escríbame a mitchell@4GuysFromRolla.com.