Información general sobre la inserción, actualización y eliminación de datos (VB)

por Scott Mitchell

Descargar PDF

En este tutorial verá cómo asignar los métodos Insert(), Update() y Delete() de ObjectDataSource a los métodos de las clases de la BLL, y cómo configurar los controles GridView, DetailsView y FormView para proporcionar funcionalidades de modificación de datos.

Introducción

En los últimos tutoriales ha examinado cómo mostrar datos en una página ASP.NET mediante los controles GridView, DetailsView y FormView. Estos controles simplemente funcionan con los datos proporcionados. Normalmente, estos controles acceden a los datos mediante un control de origen de datos, como ObjectDataSource. Ha visto cómo ObjectDataSource actúa como proxy entre la página ASP.NET y los datos subyacentes. Cuando un control GridView necesita mostrar datos, invoca el método Select() de ObjectDataSource, que a su vez invoca un método de la capa de lógica de negocios (BLL), que llama a un método del control TableAdapter de la capa de acceso a datos (DAL) correspondiente, que a su vez envía una consulta SELECT a la base de datos Northwind.

Recordemos que al crear las instancias de TableAdapter en la DAL en el primer tutorial, Visual Studio agregó automáticamente métodos para insertar, actualizar y eliminar datos de la tabla de base de datos subyacente. Además, en Creación de una capa de lógica de negocios se diseñaron métodos en la BLL que llamaban a estos métodos de la DAL de modificación de datos.

Además de su método Select(), ObjectDataSource también tiene los métodos Insert(), Update() y Delete(). Al igual que el método Select(), estos tres métodos pueden asignarse a métodos de un objeto subyacente. Cuando se configuran para insertar, actualizar o eliminar datos, los controles GridView, DetailsView y FormView proporcionan una interfaz de usuario para modificar los datos subyacentes. Esta interfaz de usuario llama a los métodos Insert(), Update() y Delete() de ObjectDataSource, que a su vez invocan a los métodos asociados del objeto subyacente (vea la figura 1).

The ObjectDataSource's Insert(), Update(), and Delete() Methods Serve as a Proxy into the BLL

Figura 1: Los métodos Insert(), Update() y Delete() de ObjectDataSource sirven de proxy a la BLL (Haga clic para ver la imagen a tamaño completo)

En este tutorial verá cómo asignar los métodos Insert(), Update() y Delete() de ObjectDataSource a métodos de clases de la BLL, y cómo configurar los controles GridView, DetailsView y FormView para proporcionar funcionalidades de modificación de datos.

Paso 1: Creación de las páginas web para insertar, actualizar y eliminar tutoriales

Antes de empezar a explorar cómo insertar, actualizar y eliminar datos, primero se crearán las páginas ASP.NET en el proyecto de sitio web necesarias para este tutorial y los siguientes. Para empezar, agregue una nueva carpeta denominada EditInsertDelete. Después, agregue las siguientes páginas ASP.NET a esa carpeta y asegúrese de asociar cada página a la página maestra Site.master:

  • Default.aspx
  • Basics.aspx
  • DataModificationEvents.aspx
  • ErrorHandling.aspx
  • UIValidation.aspx
  • CustomizedUI.aspx
  • OptimisticConcurrency.aspx
  • ConfirmationOnDelete.aspx
  • UserLevelAccess.aspx

Add the ASP.NET Pages for the Data Modification-Related Tutorials

Figura 2: Adición de las páginas ASP.NET para los tutoriales relacionados con la modificación de datos

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

Add the SectionLevelTutorialListing.ascx User Control to Default.aspx

Figura 3: Adición del control de usuario SectionLevelTutorialListing.ascx a Default.aspx (Haga clic para ver la imagen a tamaño completo)

Por último, agregue las siguientes páginas como entradas al archivo Web.sitemap. En concreto, agregue el marcado siguiente después del formato personalizado <siteMapNode>:

<siteMapNode title="Editing, Inserting, and Deleting" url="~/EditInsertDelete/Default.aspx" description="Samples of Reports that Provide Editing, Inserting, and Deleting Capabilities"> <siteMapNode url="~/EditInsertDelete/Basics.aspx" title="Basics" description="Examines the basics of data modification with the GridView, DetailsView, and FormView controls." /> <siteMapNode url="~/EditInsertDelete/DataModificationEvents.aspx" title="Data Modification Events" description="Explores the events raised by the ObjectDataSource pertinent to data modification." /> <siteMapNode url="~/EditInsertDelete/ErrorHandling.aspx" title="Error Handling" description="Learn how to gracefully handle exceptions raised during the data modification workflow." /> <siteMapNode url="~/EditInsertDelete/UIValidation.aspx" title="Adding Data Entry Validation" description="Help prevent data entry errors by providing validation." /> <siteMapNode url="~/EditInsertDelete/CustomizedUI.aspx" title="Customize the User Interface" description="Customize the editing and inserting user interfaces." /> <siteMapNode url="~/EditInsertDelete/OptimisticConcurrency.aspx" title="Optimistic Concurrency" description="Learn how to help prevent simultaneous users from overwritting one another s changes." /> <siteMapNode url="~/EditInsertDelete/ConfirmationOnDelete.aspx" title="Confirm On Delete" description="Prompt a user for confirmation when deleting a record." /> <siteMapNode url="~/EditInsertDelete/UserLevelAccess.aspx" title="Limit Capabilities Based on User" description="Learn how to limit the data modification functionality based on the user role or permissions." /> </siteMapNode>

Después de actualizar Web.sitemap, dedique un momento a ver el sitio web de los tutoriales desde un explorador. Ahora el menú de la izquierda incluye elementos para los tutoriales sobre edición, inserción y eliminación.

The Site Map Now Includes Entries for the Editing, Inserting, and Deleting Tutorials

Figura 4: El mapa del sitio incluye ahora entradas para los tutoriales de edición, inserción y eliminación

Paso 2: Adición y configuración del control ObjectDataSource

Como GridView, DetailsView y FormView difieren en sus funcionalidades y diseño de modificación de datos, se examinarán individualmente. En lugar de tener cada control con una instancia propia de ObjectDataSource, se creará un único elemento ObjectDataSource que los tres ejemplos de control pueden compartir.

Abra la página Basics.aspx, arrastre ObjectDataSource desde el Cuadro de herramientas al Diseñador y haga clic en el vínculo Configurar origen de datos desde su etiqueta inteligente. Como ProductsBLL es la única clase de la BLL que proporciona métodos de edición, inserción y eliminación, configure ObjectDataSource para que utilice esta clase.

Configure the ObjectDataSource to Use the ProductsBLL Class

Figura 5: Configuración de ObjectDataSource para usar la clase ProductsBLL (Haga clic para ver la imagen a tamaño completo)

En la siguiente pantalla puede especificar qué métodos de la clase ProductsBLL se asignan a las clases Select(), Insert(), Update() y Delete() de ObjectDataSource si selecciona la pestaña correspondiente y elige el método en la lista desplegable. En la figura 6, que ya debería resultarle familiar, se asigna el método Select() de ObjectDataSource al método GetProducts() de la clase ProductsBLL. Los métodos Insert(), Update() y Delete() se pueden configurar si se selecciona la pestaña correspondiente de la lista situada en la parte superior.

Have the ObjectDataSource Return All of the Products

Figura 6: Hacer que el ObjectDataSource devuelva todos los productos (Haga clic para ver la imagen a tamaño completo)

En las figuras 7, 8 y 9 se muestran las pestañas UPDATE, INSERT y DELETE de ObjectDataSource. Configure estas pestañas para que los métodos Insert(), Update() y Delete() invoquen a los métodos UpdateProduct, AddProduct y DeleteProduct de la clase ProductsBLL, respectivamente.

Map the ObjectDataSource's Update() Method to the ProductBLL Class's UpdateProduct Method

Figura 7: Asignación del método Update() de ObjectDataSource al método UpdateProduct de la clase ProductBLL (Haga clic para ver la imagen a tamaño completo)

Map the ObjectDataSource's Insert() Method to the ProductBLL Class's AddProduct Method

Figura 8: Asignación del método Insert() de ObjectDataSource al método Product de la clase ProductBLL (Haga clic para ver la imagen a tamaño completo)

Map the ObjectDataSource's Delete() Method to the ProductBLL Class's DeleteProduct Method

Figura 9: Asignación del método Delete() de ObjectDataSource al método DeleteProduct de la clase ProductBLL (Haga clic para ver la imagen a tamaño completo)

Es posible que haya observado que las listas desplegables de las pestañas UPDATE, INSERT y DELETE ya tenían estos métodos seleccionados. Esto es gracias al uso de DataObjectMethodAttribute que decora los métodos de ProductsBLL. Por ejemplo, el método DeleteProduct tiene la siguiente firma:

<System.ComponentModel.DataObjectMethodAttribute _ (System.ComponentModel.DataObjectMethodType.Delete, True)> _ Public Function DeleteProduct(ByVal productID As Integer) As Boolean End Function

El atributo DataObjectMethodAttribute indica el propósito de cada método, si es para seleccionar, insertar, actualizar o eliminar, y si es o no el valor predeterminado. Si ha omitido estos atributos al crear las clases de la BLL, deberá seleccionar manualmente los métodos de las pestañas UPDATE, INSERT y DELETE.

Tras asegurarse de que los métodos ProductsBLL apropiados se asignan a los métodos Insert(), Update() y Delete() de ObjectDataSource, haga clic en Finalizar para completar el asistente.

Examen del marcado de ObjectDataSource

Después de configurar ObjectDataSource mediante su asistente, vaya a la vista Origen para examinar el marcado declarativo generado. La etiqueta <asp:ObjectDataSource> especifica el objeto subyacente y los métodos que se van a invocar. Además, hay elementos DeleteParameters, UpdateParameters y InsertParameters que se asignan a los parámetros de entrada para los métodos AddProduct, UpdateProduct y DeleteProduct de la clase ProductsBLL:

<asp:ObjectDataSource ID="ObjectDataSource1" runat="server" DeleteMethod="DeleteProduct" InsertMethod="AddProduct" OldValuesParameterFormatString="original_{0}" SelectMethod="GetProducts" TypeName="ProductsBLL" UpdateMethod="UpdateProduct"> <DeleteParameters> <asp:Parameter Name="productID" Type="Int32" /> </DeleteParameters> <UpdateParameters> <asp:Parameter Name="productName" Type="String" /> <asp:Parameter Name="supplierID" Type="Int32" /> <asp:Parameter Name="categoryID" Type="Int32" /> <asp:Parameter Name="quantityPerUnit" Type="String" /> <asp:Parameter Name="unitPrice" Type="Decimal" /> <asp:Parameter Name="unitsInStock" Type="Int16" /> <asp:Parameter Name="unitsOnOrder" Type="Int16" /> <asp:Parameter Name="reorderLevel" Type="Int16" /> <asp:Parameter Name="discontinued" Type="Boolean" /> <asp:Parameter Name="productID" Type="Int32" /> </UpdateParameters> <InsertParameters> <asp:Parameter Name="productName" Type="String" /> <asp:Parameter Name="supplierID" Type="Int32" /> <asp:Parameter Name="categoryID" Type="Int32" /> <asp:Parameter Name="quantityPerUnit" Type="String" /> <asp:Parameter Name="unitPrice" Type="Decimal" /> <asp:Parameter Name="unitsInStock" Type="Int16" /> <asp:Parameter Name="unitsOnOrder" Type="Int16" /> <asp:Parameter Name="reorderLevel" Type="Int16" /> <asp:Parameter Name="discontinued" Type="Boolean" /> </InsertParameters> </asp:ObjectDataSource>

ObjectDataSource incluye un parámetro para cada uno de los parámetros de entrada de sus métodos asociados, al igual que una lista de SelectParameter está presente cuando ObjectDataSource está configurado para llamar a un método select que espera un parámetro de entrada (como GetProductsByCategoryID(categoryID)). Como verá en breve, GridView, DetailsView y FormView establecen automáticamente los valores para estos DeleteParameters, UpdateParameters y InsertParameters antes de invocar el método Insert(), Update() o Delete() de ObjectDataSource. Estos valores también se pueden establecer mediante programación según sea necesario, como se analizará en un tutorial futuro.

Un efecto secundario de utilizar el asistente para configurar ObjectDataSource es que Visual Studio establece la propiedad OldValuesParameterFormatString en original_{0}. Este valor de propiedad se usa para incluir los valores originales de los datos que se editan y es útil en dos escenarios:

  • Si, al editar un registro, los usuarios pueden cambiar el valor de clave principal. En este caso, se deben proporcionar tanto el nuevo valor de clave principal como el valor de clave principal original para que se pueda encontrar el registro con el valor de clave principal original y que su valor se actualice en consecuencia.
  • Al usar la simultaneidad optimista. La simultaneidad optimista es una técnica para asegurarse de que dos usuarios simultáneos no sobrescriben los cambios de otro y es el tema de un tutorial futuro.

La propiedad OldValuesParameterFormatString indica el nombre de los parámetros de entrada en los métodos update y delete del objeto subyacente para los valores originales. Esta propiedad y su propósito se analizarán con más detalle al explorar la simultaneidad optimista. Pero se menciona ahora porque los métodos de la BLL no esperan los valores originales y, por tanto, es importante eliminar esta propiedad. Si se deja la propiedad OldValuesParameterFormatString con un valor distinto del predeterminado ({0}), se producirá un error cuando un control web de datos intente invocar los métodos Update() o Delete() de ObjectDataSource, ya que este intentará pasar tanto los parámetros UpdateParameters o DeleteParameters especificados como el valor original.

Si esto no está muy claro en este momento, no se preocupe, esta propiedad y su utilidad se describirán en un tutorial posterior. Por ahora, simplemente asegúrese de eliminar esta declaración de propiedad completamente de la sintaxis declarativa o establecer el valor en el valor predeterminado ({0}).

Nota:

Si simplemente borra el valor de propiedad OldValuesParameterFormatString de la ventana Propiedades en la vista Diseño, la propiedad seguirá existiendo en la sintaxis declarativa, pero se establecerá en una cadena vacía. Esto, desafortunadamente, seguirá teniendo como resultado el mismo problema descrito anteriormente. Por tanto, quite la propiedad por completo de la sintaxis declarativa o, en la ventana Propiedades, establezca el valor en el valor predeterminado, {0}.

Paso 3: Adición de un control web de datos y configuración para la modificación de datos

Una vez que ObjectDataSource se ha agregado a la página y se ha configurado, ya puede agregar controles web de datos a la página para mostrar los datos y proporcionar un medio para que el usuario final los modifique. Se describirán por separado GridView, DetailsView y FormView, ya que estos controles web de datos difieren en sus funcionalidades y configuración de modificación de datos.

Como verá en el resto de este artículo, agregar compatibilidad básica de edición, inserción y eliminación mediante los controles GridView, DetailsView y FormView es realmente tan sencillo como activar un par de casillas. Hay muchas sutilezas y casos perimetrales en el mundo real que hacen que proporcionar esa funcionalidad sea más compleja que simplemente apuntar y hacer clic. Pero este tutorial se centra únicamente en probar las funcionalidades de modificación de datos simplistas. En tutoriales posteriores se examinarán las preocupaciones que sin duda surgirán en un entorno real.

Eliminación de datos de GridView

Para empezar, arrastre un control GridView desde el Cuadro de herramientas al Diseñador. A continuación, enlace ObjectDataSource a GridView; para ello, debe seleccionarlo en la lista desplegable de la etiqueta inteligente de GridView. En este momento, el marcado declarativo de GridView será el siguiente:

<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False" DataKeyNames="ProductID" DataSourceID="ObjectDataSource1"> <Columns> <asp:BoundField DataField="ProductID" HeaderText="ProductID" InsertVisible="False" ReadOnly="True" SortExpression="ProductID" /> <asp:BoundField DataField="ProductName" HeaderText="ProductName" SortExpression="ProductName" /> <asp:BoundField DataField="SupplierID" HeaderText="SupplierID" SortExpression="SupplierID" /> <asp:BoundField DataField="CategoryID" HeaderText="CategoryID" SortExpression="CategoryID" /> <asp:BoundField DataField="QuantityPerUnit" HeaderText="QuantityPerUnit" SortExpression="QuantityPerUnit" /> <asp:BoundField DataField="UnitPrice" HeaderText="UnitPrice" SortExpression="UnitPrice" /> <asp:BoundField DataField="UnitsInStock" HeaderText="UnitsInStock" SortExpression="UnitsInStock" /> <asp:BoundField DataField="UnitsOnOrder" HeaderText="UnitsOnOrder" SortExpression="UnitsOnOrder" /> <asp:BoundField DataField="ReorderLevel" HeaderText="ReorderLevel" SortExpression="ReorderLevel" /> <asp:CheckBoxField DataField="Discontinued" HeaderText="Discontinued" SortExpression="Discontinued" /> <asp:BoundField DataField="CategoryName" HeaderText="CategoryName" ReadOnly="True" SortExpression="CategoryName" /> <asp:BoundField DataField="SupplierName" HeaderText="SupplierName" ReadOnly="True" SortExpression="SupplierName" /> </Columns> </asp:GridView>

El enlace de GridView a ObjectDataSource desde su etiqueta inteligente tiene dos ventajas:

  • Se crean automáticamente controles BoundField y CheckBoxField para cada uno de los campos devueltos por ObjectDataSource. Además, las propiedades de los controles BoundField y CheckBoxField se establecen en función de los metadatos del campo subyacente. Por ejemplo, los campos ProductID, CategoryName y SupplierName están marcados como de solo lectura en ProductsDataTable y, por tanto, no deberían poder actualizarse durante la edición. Para ello, las propiedades ReadOnly de estos controles BoundField se establecen en True.
  • La propiedad DataKeyNames se asigna al campo o campos de clave principal del objeto subyacente. Esto es esencial cuando se usa GridView para editar o eliminar datos, ya que esta propiedad indica el campo (o conjunto de campos) que identifica cada registro de forma única. Para más información sobre la propiedad DataKeyNames, consulte de nuevo el tutorial Maestro y detalles mediante un control GridView maestro seleccionable con un control DetailView de detalles.

Aunque GridView se puede vincular a ObjectDataSource desde la ventana Propiedades o con la sintaxis declarativa, para hacerlo es necesario añadir manualmente el control BoundField y el marcado de DataKeyNames adecuados.

El control GridView proporciona compatibilidad integrada para la edición y eliminación de nivel de fila. La configuración de GridView para admitir la eliminación agrega una columna de botones Eliminar. Cuando el usuario final hace clic en el botón Eliminar de una fila determinada, se produce un postback y GridView realiza los pasos siguientes:

  1. Se asignan los valores DeleteParameters de ObjectDataSource
  2. Se invoca el método Delete() de ObjectDataSource y se elimina el registro especificado
  3. GridView se vuelve a vincular a ObjectDataSource mediante la invocación de su método Select()

Los valores asignados aDeleteParameters son los valores de los campos DataKeyNames de la fila cuyo botón Eliminar se ha pulsado. Por tanto, es vital que la propiedad DataKeyNames de un control GridView se establezca correctamente. Si falta, a DeleteParameters se le asignará un valor Nothing en el paso 1, lo que a su vez no dará lugar a ningún registro eliminado en el paso 2.

Nota:

La colección DataKeys se almacena en el estado de control de GridView, lo que significa que los valores DataKeys se recordarán entre postback incluso si el estado de visualización de GridView se ha desactivado. Pero es muy importante que el estado de visualización permanezca habilitado para los controles GridView que admiten la edición o eliminación (el comportamiento predeterminado). Si establece la propiedad EnableViewState de GridView en false, el comportamiento de edición y eliminación funcionará correctamente para un único usuario, pero si hay usuarios simultáneos que eliminan datos, existe la posibilidad de que eliminen o editen accidentalmente registros que no tenían previsto.

Esta misma advertencia también se aplica a las instancias de DetailsView y FormView.

Para agregar funcionalidades de eliminación a GridView, simplemente vaya a su etiqueta inteligente y active la casilla Habilitar eliminación.

Check the Enable Deleting Checkbox

Figura 10: Activación de la casilla Habilitar eliminación

Al activar la casilla Habilitar eliminación de la etiqueta inteligente, se agrega un elemento CommandField al control GridView. CommandField representa una columna en GridView con botones para realizar una o varias de las tareas siguientes: seleccionar un registro, editar un registro y eliminar un registro. Anteriormente ha visto CommandField en acción con la selección de registros en el tutorial Maestro y detalles mediante un control GridView maestro seleccionable con un control DetailView de detalles.

CommandField contiene una serie de propiedades ShowXButton que indican qué serie de botones muestra. Al activar la casilla Habilitar eliminación se ha añadido una instancia de CommandField cuya propiedad ShowDeleteButton es True a la colección Columnas de GridView.

<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False" DataKeyNames="ProductID" DataSourceID="ObjectDataSource1"> <Columns> <asp:CommandField ShowDeleteButton="True" /> ... BoundFields removed for brevity ... </Columns> </asp:GridView>

En este punto, lo crea o no, ha terminado de añadir compatibilidad con la eliminación al control GridView. Como se muestra en la figura 11, al visitar esta página desde un explorador hay una columna de botones Eliminar.

The CommandField Adds a Column of Delete Buttons

Figura 11: CommandField agrega una columna de botones de eliminación (Haga clic para ver la imagen a tamaño completo)

Si ha seguido este tutorial desde cero por su cuenta, al probar esta página y hacer clic en el botón Eliminar se generará una excepción. Siga leyendo para obtener información sobre por qué se generan estas excepciones y cómo corregirlas.

Nota:

Si sigue las explicaciones con la descarga que acompaña a este tutorial, estos problemas ya se han tenido en cuenta. Pero le recomendamos que lea los detalles que se enumeran a continuación para identificar problemas que pueden surgir y soluciones alternativas adecuadas.

Si, al intentar eliminar un producto, se inicia una excepción cuyo mensaje es similar a "ObjectDataSource "ObjectDataSource1" no pudo encontrar un método no genérico "DeleteProduct" que tenga los parámetros: productID, original_ProductID", es probable que haya olvidado eliminar la propiedad OldValuesParameterFormatString de ObjectDataSource. Con la propiedad OldValuesParameterFormatString especificada, ObjectDataSource intenta pasar los parámetros de entrada productID y original_ProductID al método DeleteProduct. Pero DeleteProduct solo acepta un único parámetro de entrada, de ahí la excepción. Al eliminar la propiedad OldValuesParameterFormatString (o al establecerla en {0}) se indica a ObjectDataSource que no intente pasar el parámetro de entrada original.

Ensure That the OldValuesParameterFormatString Property Has Been Cleared Out

Figura 12: Comprobación de que la propiedad OldValuesParameterFormatString se ha borrado (Haga clic para ver la imagen a tamaño completo)

Aunque hubiera eliminado la propiedad OldValuesParameterFormatString, se seguirá iniciando una excepción al intentar eliminar un producto con el mensaje "La instrucción DELETE ha entrado en conflicto con la restricción REFERENCE "FK_Order_Details_Products"". La base de datos Northwind contiene una restricción de clave externa entre las tablas Order Details y Products, lo que significa que un producto no puede eliminarse del sistema si existen uno o más registros del mismo en la tabla Order Details. Como cada producto de la base de datos Northwind tiene al menos un registro en Order Details, no se puede eliminar ningún producto hasta que no se eliminen primero los registros de detalles del pedido asociados al producto.

A Foreign Key Constraint Prohibits the Deletion of Products

Figura 13: Una restricción de clave externa prohíbe la eliminación de productos (Haga clic para ver la imagen a tamaño completo)

En el tutorial, se eliminarán todos los registros de la tabla Order Details. En una aplicación real, tendría que hacer lo siguiente:

  • Tener otra pantalla para administrar la información de detalles del pedido
  • Aumentar el método DeleteProduct para incluir lógica para eliminar los detalles del pedido del producto especificado
  • Modificar la consulta SQL utilizada por TableAdapter para incluir la eliminación de los detalles del pedido del producto especificado

Ahora se eliminarán todos los registros de la tabla Order Details para eludir la restricción de clave externa. Vaya al Explorador de servidores en Visual Studio, haga clic con el botón derecho en el nodo NORTHWND.MDF y seleccione Nueva consulta. Después, en la ventana de consulta, ejecute la siguiente instrucción SQL: DELETE FROM [Order Details]

Delete All Records from the Order Details Table

Figura 14: Eliminación de todos los registros de la tabla Order Details (Haga clic para ver la imagen a tamaño completo)

Tras borrar la tabla Order Details, al hacer clic en el botón Eliminar se borrará el producto sin error. Si al hacer clic en el botón Eliminar no se elimina el producto, compruebe que la propiedad DataKeyNames de GridView está establecida en el campo de clave principal (ProductID).

Nota:

Al hacer clic en el botón Eliminar, se produce un postback y se elimina el registro. Esto puede ser peligroso, ya que es fácil hacer clic accidentalmente en el botón Eliminar de la fila incorrecta. En un tutorial posterior verá cómo agregar una confirmación del lado cliente al eliminar un registro.

Edición de datos con GridView

Junto con la eliminación, el control GridView también proporciona compatibilidad integrada de edición de nivel de fila. La configuración de GridView para admitir la edición agrega una columna de botones Editar. Desde la perspectiva del usuario final, al hacer clic en el botón Editar de una fila hace que esa fila se pueda editar, se convierten las celdas en cuadros de texto que contienen los valores existentes y se reemplaza el botón Editar por los botones Actualizar y Cancelar. Después de realizar los cambios deseados, el usuario final puede hacer clic en el botón Actualizar para confirmar los cambios, o en el botón Cancelar para descartarlos. En cualquier caso, después de hacer clic en Actualizar o Cancelar, GridView vuelve a su estado anterior a la edición.

Desde la perspectiva de un desarrollador de páginas, cuando el usuario final hace clic en el botón Editar de una fila determinada, se produce un postback y GridView realiza los pasos siguientes:

  1. La propiedad EditItemIndex de GridView se asigna al índice de la fila cuyo botón Editar se ha pulsado
  2. GridView se vuelve a vincular a ObjectDataSource mediante la invocación de su método Select()
  3. El índice de la fila que coincide con EditItemIndex se representa en "modo de edición". En este modo, el botón Editar se sustituye por los botones Actualizar y Cancelar, y los controles BoundField cuyas propiedades ReadOnly son False (el valor predeterminado) se representan como controles web TextBox cuyas propiedades Text se asignan a los valores de los campos de datos.

En este momento, el marcado se devuelve al explorador, lo que permite al usuario final realizar cambios en los datos de la fila. Cuando el usuario hace clic en el botón Actualizar, se produce un postback y GridView realiza los pasos siguientes:

  1. A los valores UpdateParameters de ObjectDataSource se les asignan los valores introducidos por el usuario final en la interfaz de edición de GridView
  2. Se invoca el método Update() de ObjectDataSource y se actualiza el registro especificado
  3. GridView se vuelve a vincular a ObjectDataSource mediante la invocación de su método Select()

Los valores de clave principal asignados a UpdateParameters en el paso 1 proceden de los valores especificados en la propiedad DataKeyNames, mientras que los valores de clave no principal proceden del texto de los controles web TextBox de la fila editada. Como sucedía con la eliminación, es vital que la propiedad DataKeyNames de un control GridView esté correctamente configurada. Si falta, al valor UpdateParameters de la clave principal se le asignará un valor Nothing en el paso 1, lo que a su vez no dará lugar a ningún registro actualizado en el paso 2.

La funcionalidad de edición se puede activar simplemente sise activa la casilla Habilitar edición en la etiqueta inteligente del control GridView.

Check the Enable Editing Checkbox

Figura 15: Activación de la casilla Habilitar edición

Al activar la casilla Habilitar edición se añadirá una instancia de CommandField (si es necesario) y se establecerá su propiedad ShowEditButton en True. Como ha visto antes, CommandField contiene una serie de propiedades ShowXButton que indican qué serie de botones muestra. Al activar la casilla Habilitar edición se añade la propiedad ShowEditButton a la instancia de CommandField existente:

<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False" DataKeyNames="ProductID" DataSourceID="ObjectDataSource1"> <Columns> <asp:CommandField ShowDeleteButton="True" ShowEditButton="True" /> ... BoundFields removed for brevity ... </Columns> </asp:GridView>

Es todo lo que hay que hacer para agregar compatibilidad rudimentaria con la edición. Como se muestra en la figura 16, la interfaz de edición es bastante básica, cada control BoundField cuya propiedad ReadOnly se establece en False (el valor predeterminado) se representa como un control TextBox. Esto incluye campos como CategoryID y SupplierID, que son claves de otras tablas.

Clicking Chai s Edit Button Displays the Row in Edit Mode

Figura 16: Al hacer clic en el botón de edición de Chai se muestra la fila en modo de edición (Haga clic para ver la imagen a tamaño completo)

Además de pedir a los usuarios que editen directamente los valores de clave externa, la interfaz de edición presenta las siguientes carencias:

  • Si el usuario escribe un valor CategoryID o SupplierID que no existe en la base de datos, UPDATE infringirá una restricción de clave externa y se iniciará una excepción.
  • La interfaz de edición no incluye ninguna validación. Si no proporciona un valor obligatorio (como ProductName), o introduce un valor de cadena donde se espera un valor numérico (como escribir "¡Demasiado!" en el cuadro texto UnitPrice), se iniciará una excepción. En un tutorial posterior se examinará cómo agregar controles de validación a la interfaz de usuario de edición.
  • Actualmente, todos los campos de producto que no sean de solo lectura deben incluirse en el control GridView. Si eliminara un campo de GridView, por ejemplo UnitPrice, al actualizar los datos GridView no establecería el valor UnitPriceUpdateParameters, lo que cambiaría el valor UnitPrice del registro de la base de datos a un valor NULL. Del mismo modo, si se elimina de GridView un campo obligatorio, como ProductName, se produciría un error de actualización con la misma excepción "Column "ProductName" does not allow nulls" mencionada antes.
  • El formato de la interfaz de edición deja mucho que desear. UnitPrice se muestra con cuatro decimales. Lo ideal sería que los valores CategoryID y SupplierID contuvieran listas desplegables que enumeraran las categorías y los proveedores del sistema.

Son deficiencias con las que tendrá que vivir por ahora, pero se abordarán en tutoriales posteriores.

Inserción, edición y eliminación de datos con DetailsView

Como ha visto en los tutoriales anteriores, el control DetailsView muestra un registro cada vez y, como GridView, permite editar y eliminar el registro mostrado actualmente. Tanto la experiencia del usuario final con la edición y eliminación de elementos de un control DetailsView como el flujo de trabajo desde el lado de ASP.NET son idénticos a los de GridView. En lo que difiere DetailsView de GridView es en que también proporciona compatibilidad integrada con la inserción.

Para demostrar las funcionalidades de modificación de datos de GridView, agregue un control DetailsView a la página Basics.aspx por encima del control GridView existente y enlácelo a la instancia de ObjectDataSource existente desde la etiqueta inteligente de DetailsView. A continuación, elimine las propiedades Height y Width de DetailsView y active la opción Habilitar paginación de la etiqueta inteligente. Para habilitar la compatibilidad con la edición, inserción y eliminación, simplemente active las casillas Habilitar edición, Habilitar inserción y Habilitar eliminación en la etiqueta inteligente.

Screenshot showing the DetailsView Tasks window with the Enable Inserting, Enable Editing, and Enable Deleting checkboxes selected.

Figura 17: Configuración de DetailsView para admitir las operaciones de edición, inserción y eliminación

Al igual que con GridView, al agregar compatibilidad con las operaciones de edición, inserción o eliminación se agrega una instancia de CommandField a DetailsView, como se muestra en la sintaxis declarativa siguiente:

<asp:DetailsView ID="DetailsView1" runat="server" AutoGenerateRows="False" DataKeyNames="ProductID" DataSourceID="ObjectDataSource1" AllowPaging="True"> <Fields> <asp:BoundField DataField="ProductID" HeaderText="ProductID" InsertVisible="False" ReadOnly="True" SortExpression="ProductID" /> <asp:BoundField DataField="ProductName" HeaderText="ProductName" SortExpression="ProductName" /> <asp:BoundField DataField="SupplierID" HeaderText="SupplierID" SortExpression="SupplierID" /> <asp:BoundField DataField="CategoryID" HeaderText="CategoryID" SortExpression="CategoryID" /> <asp:BoundField DataField="QuantityPerUnit" HeaderText="QuantityPerUnit" SortExpression="QuantityPerUnit" /> <asp:BoundField DataField="UnitPrice" HeaderText="UnitPrice" SortExpression="UnitPrice" /> <asp:BoundField DataField="UnitsInStock" HeaderText="UnitsInStock" SortExpression="UnitsInStock" /> <asp:BoundField DataField="UnitsOnOrder" HeaderText="UnitsOnOrder" SortExpression="UnitsOnOrder" /> <asp:BoundField DataField="ReorderLevel" HeaderText="ReorderLevel" SortExpression="ReorderLevel" /> <asp:CheckBoxField DataField="Discontinued" HeaderText="Discontinued" SortExpression="Discontinued" /> <asp:BoundField DataField="CategoryName" HeaderText="CategoryName" ReadOnly="True" SortExpression="CategoryName" /> <asp:BoundField DataField="SupplierName" HeaderText="SupplierName" ReadOnly="True" SortExpression="SupplierName" /> <asp:CommandField ShowDeleteButton="True" ShowEditButton="True" ShowInsertButton="True" /> </Fields> </asp:DetailsView>

Tenga en cuenta que para DetailsView el elemento CommandField aparece al final de la colección Columns de forma predeterminada. Como los campos de DetailsView se representan como filas, CommandField aparece como una fila con los botones Insertar, Editar y Eliminar en la parte inferior de DetailsView.

Screenshot of the DetailsView with the CommandField appearing as a bottom row with Insert, Edit, and Delete buttons.

Figura 18: Configuración de DetailsView para permitir editar, insertar y eliminar (Haga clic para ver la imagen a tamaño completo)

Al hacer clic en el botón Eliminar, se inicia la misma secuencia de eventos que con GridView: un postback; seguido de que DetailsView rellene el valor DeleteParameters de ObjectDataSource en función de los valores de DataKeyNames; junto con una llamada al método Delete() de ObjectDataSource, que elimina realmente el producto de la base de datos. La edición en DetailsView también funciona de forma idéntica a la de GridView.

Para insertar, se presenta al usuario final un botón Nuevo que, cuando se hace clic, representa DetailsView en "modo de inserción". Con el "modo de inserción", el botón Nuevo se sustituye por los botones Insertar y Cancelar, y solo se muestran los controles BoundField cuya propiedad InsertVisible esté establecida en True (el valor predeterminado). Los campos de datos identificados como campos de incremento automático, como ProductID, tienen su propiedad InsertVisible establecida en False cuando DetailsView se enlaza al origen de datos desde la etiqueta inteligente.

Al enlazar un origen de datos a un control DetailsView mediante la etiqueta inteligente, Visual Studio establece la propiedad InsertVisible en False solo para los campos de incremento automático. Los campos de solo lectura, como CategoryName y SupplierName, se mostrarán en la interfaz de usuario del "modo de inserción" a menos que su propiedad InsertVisible se establezca explícitamente en False. Tómese un momento para establecer las propiedades InsertVisible de estos dos campos en False, ya sea mediante la sintaxis declarativa de DetailsView o desde el enlace Editar campos de la etiqueta inteligente. En la figura 19 se muestra el establecimiento de las propiedades InsertVisible en False al hacer clic en el enlace Editar campos.

Screenshot showing the Fields window with the InsertVisible property set to False.

Figura 19: Northwind Traders ofrece ahora té Acme (Haga clic para ver la imagen a tamaño completo)

Tras establecer las propiedades InsertVisible, vea la página Basics.aspx en un explorador y haga clic en el botón Nuevo. En la figura 20 se muestra el control DetailsView al añadir una nueva bebida, Acme Tea, a la línea de productos.

Screenshot showing the DetailsView of the Basics.aspx page in a web browser.

Figura 20: Northwind Traders ofrece ahora té Acme (Haga clic para ver la imagen a tamaño completo)

Tras introducir los datos de Acme Tea y hacer clic en el botón Insertar, se produce un postback y el nuevo registro se añade a la tabla de base de datos Products. Como en esta vista de detalles se enumeran los productos en orden con los que existen en la tabla de base de datos, se debe paginar al último producto para ver el nuevo producto.

Details for Acme Tea

Figura 21: Detalles de Acme Tea (Haga clic para ver la imagen a tamaño completo)

Nota:

La propiedad CurrentMode de DetailsView indica la interfaz que se muestra y puede ser uno de los siguientes valores: Edit, Insert o ReadOnly. La propiedad DefaultMode indica el modo al que vuelve DetailsView una vez que finaliza una edición o inserción, y es útil para mostrar un control DetailsView que está permanentemente en modo edición o inserción.

Las funciones de inserción y edición mediante apuntar y hacer clic de DetailsView presentan las mismas limitaciones que en GridView: el usuario debe introducir los valores CategoryID y SupplierID existentes desde un cuadro de texto; la interfaz carece de toda lógica de validación; todos los campos de producto que no admiten valores NULL o no tienen un valor predeterminado especificado a nivel de la base de datos deben incluirse en la interfaz de inserción, etc.

Las técnicas que se verán para ampliar y mejorar la interfaz de edición de GridView en artículos posteriores también se pueden aplicar a las interfaces de edición e inserción del control DetailsView.

Uso de FormView para una interfaz de usuario de modificación de datos más flexible

FormView ofrece compatibilidad integrada para insertar, editar y eliminar datos, pero como usa plantillas en lugar de campos, no hay ningún lugar para agregar los elementos BoundField o CommandField usados por los controles GridView y DetailsView para proporcionar la interfaz de modificación de datos. En su lugar, sirve interfaz para los controles web para recopilar entradas de usuario al agregar un nuevo elemento o editar uno existente junto con los botones Nuevo, Editar, Eliminar, Insertar, Actualizar y Cancelar se deben agregar manualmente a las plantillas adecuadas. Afortunadamente, Visual Studio creará automáticamente la interfaz necesaria al enlazar FormView a un origen de datos desde la lista desplegable de su etiqueta inteligente.

Para ilustrar estas técnicas, agregue primero una instancia de FormView a la página Basics.aspx y, desde su etiqueta inteligente, enlácelo a la instancia de ObjectDataSource ya creada. Esto generará EditItemTemplate, InsertItemTemplate y ItemTemplate para FormView con controles web TextBox para recopilar la entrada del usuario y controles web Button para los botones Nuevo, Editar, Eliminar, Insertar, Actualizar y Cancelar. Además, la propiedad DataKeyNames de FormView se establece en el campo de clave principal (ProductID) del objeto devuelto por ObjectDataSource. Por último, active la opción Habilitar paginación en la etiqueta inteligente de FormView.

A continuación se muestra el marcado declarativo para ItemTemplate de FormView después de que se haya enlazado a ObjectDataSource. De forma predeterminada, cada campo de producto de valor no booleano se enlaza a la propiedad Text de un control web Label, mientras que cada campo de valor booleano (Discontinued) se enlaza a la propiedad Checked de un control web CheckBox desactivado. Para que los botones Nuevo, Editar y Eliminar activen determinados comportamientos de FormView al hacer clic en ellos, es imprescindible que sus valores CommandName se establezcan en New, Edit y Delete, respectivamente.

<asp:FormView ID="FormView1" runat="server" DataKeyNames="ProductID" DataSourceID="ObjectDataSource1" AllowPaging="True"> <EditItemTemplate> ... </EditItemTemplate> <InsertItemTemplate> ... </InsertItemTemplate> <ItemTemplate> ProductID: <asp:Label ID="ProductIDLabel" runat="server" Text='<%# Eval("ProductID") %>'></asp:Label><br /> ProductName: <asp:Label ID="ProductNameLabel" runat="server" Text='<%# Bind("ProductName") %>'> </asp:Label><br /> SupplierID: <asp:Label ID="SupplierIDLabel" runat="server" Text='<%# Bind("SupplierID") %>'> </asp:Label><br /> CategoryID: <asp:Label ID="CategoryIDLabel" runat="server" Text='<%# Bind("CategoryID") %>'> </asp:Label><br /> QuantityPerUnit: <asp:Label ID="QuantityPerUnitLabel" runat="server" Text='<%# Bind("QuantityPerUnit") %>'> </asp:Label><br /> UnitPrice: <asp:Label ID="UnitPriceLabel" runat="server" Text='<%# Bind("UnitPrice") %>'></asp:Label><br /> UnitsInStock: <asp:Label ID="UnitsInStockLabel" runat="server" Text='<%# Bind("UnitsInStock") %>'> </asp:Label><br /> UnitsOnOrder: <asp:Label ID="UnitsOnOrderLabel" runat="server" Text='<%# Bind("UnitsOnOrder") %>'> </asp:Label><br /> ReorderLevel: <asp:Label ID="ReorderLevelLabel" runat="server" Text='<%# Bind("ReorderLevel") %>'> </asp:Label><br /> Discontinued: <asp:CheckBox ID="DiscontinuedCheckBox" runat="server" Checked='<%# Bind("Discontinued") %>' Enabled="false" /><br /> CategoryName: <asp:Label ID="CategoryNameLabel" runat="server" Text='<%# Bind("CategoryName") %>'> </asp:Label><br /> SupplierName: <asp:Label ID="SupplierNameLabel" runat="server" Text='<%# Bind("SupplierName") %>'> </asp:Label><br /> <asp:LinkButton ID="EditButton" runat="server" CausesValidation="False" CommandName="Edit" Text="Edit"> </asp:LinkButton> <asp:LinkButton ID="DeleteButton" runat="server" CausesValidation="False" CommandName="Delete" Text="Delete"> </asp:LinkButton> <asp:LinkButton ID="NewButton" runat="server" CausesValidation="False" CommandName="New" Text="New"> </asp:LinkButton> </ItemTemplate> </asp:FormView>

En la figura 22 se muestra ItemTemplate de FormView visto en un explorador. Cada campo de producto aparece con los botones Nuevo, Editar y Eliminar en la parte inferior.

The Defaut FormView ItemTemplate Lists Each Product Field Along with New, Edit, and Delete Buttons

Figura 22: El control FormView ItemTemplate predeterminado enumera cada campo de producto junto con los botones Nuevo, Editar y Eliminar (Haga clic para ver la imagen a tamaño completo)

Como sucede con GridView y DetailsView, al hacer clic en el botón Eliminar o en cualquier control Button, LinkButton o ImageButton cuya propiedad CommandName esté establecida en Eliminar se produce un postback, se rellena DeleteParameters de ObjectDataSource en función del valor DataKeyNames de FormView y se invoca el método Delete() de ObjectDataSource.

Cuando se pulsa el botón Editar se produce un postback y los datos vuelven a EditItemTemplate, que se encarga de representar la interfaz de edición. Esta interfaz incluye los controles web para editar datos junto con los botones Actualizar y Cancelar. El valor EditItemTemplate generado de manera predeterminada por Visual Studio contiene un control Label para cualquier campo de autoincremento (ProductID), un control TextBox para cada campo de valor no booleano y un control CheckBox para cada campo de valor booleano. Este comportamiento es muy similar al de los controles BoundField generados de forma automática en los controles GridView y DetailsView.

Nota:

Un pequeño problema con la generación automática de EditItemTemplate en FormView es que genera controles web TextBox para campos que son de solo lectura, como CategoryName y SupplierName. En breve se verá cómo solucionarlo.

Los controles TextBox de EditItemTemplate tienen su propiedad Text enlazada al valor de su campo de datos correspondiente mediante el enlace de datos bidireccional. El enlace de datos bidireccional, indicado por <%# Bind("dataField") %>, realiza el enlace de datos al enlazar datos a la plantilla y al rellenar los parámetros de ObjectDataSource para insertar o editar registros. Es decir, cuando el usuario pulsa el botón Editar de ItemTemplate, el método Bind() devuelve el valor del campo de datos especificado. Después de que el usuario realice sus cambios y haga clic en Actualizar, los valores devueltos que se corresponden a los campos de datos especificados mediante Bind() se aplican a UpdateParameters de ObjectDataSource. Alternativamente, el enlace de datos unidireccional, indicado por <%# Eval("dataField") %>, solo recupera los valores de los campos de datos cuando se enlazan datos a la plantilla y no devuelve los valores introducidos por el usuario a los parámetros del origen de datos en el postback.

En el siguiente marcado declarativo se muestra el elemento EditItemTemplate de FormView. Observe que aquí se utiliza el método Bind() en la sintaxis de enlace de datos y que los controles web Button Actualizar y Cancelar tienen sus propiedades CommandName establecidas en consecuencia.

<asp:FormView ID="FormView1" runat="server" DataKeyNames="ProductID" DataSourceID="ObjectDataSource1" AllowPaging="True"> <EditItemTemplate> ProductID: <asp:Label ID="ProductIDLabel1" runat="server" Text="<%# Eval("ProductID") %>"></asp:Label><br /> ProductName: <asp:TextBox ID="ProductNameTextBox" runat="server" Text="<%# Bind("ProductName") %>"> </asp:TextBox><br /> SupplierID: <asp:TextBox ID="SupplierIDTextBox" runat="server" Text="<%# Bind("SupplierID") %>"> </asp:TextBox><br /> CategoryID: <asp:TextBox ID="CategoryIDTextBox" runat="server" Text="<%# Bind("CategoryID") %>"> </asp:TextBox><br /> QuantityPerUnit: <asp:TextBox ID="QuantityPerUnitTextBox" runat="server" Text="<%# Bind("QuantityPerUnit") %>"> </asp:TextBox><br /> UnitPrice: <asp:TextBox ID="UnitPriceTextBox" runat="server" Text="<%# Bind("UnitPrice") %>"> </asp:TextBox><br /> UnitsInStock: <asp:TextBox ID="UnitsInStockTextBox" runat="server" Text="<%# Bind("UnitsInStock") %>"> </asp:TextBox><br /> UnitsOnOrder: <asp:TextBox ID="UnitsOnOrderTextBox" runat="server" Text="<%# Bind("UnitsOnOrder") %>"> </asp:TextBox><br /> ReorderLevel: <asp:TextBox ID="ReorderLevelTextBox" runat="server" Text="<%# Bind("ReorderLevel") %>"> </asp:TextBox><br /> Discontinued: <asp:CheckBox ID="DiscontinuedCheckBox" runat="server" Checked="<%# Bind("Discontinued") %>" /><br /> CategoryName: <asp:TextBox ID="CategoryNameTextBox" runat="server" Text="<%# Bind("CategoryName") %>"> </asp:TextBox><br /> SupplierName: <asp:TextBox ID="SupplierNameTextBox" runat="server" Text="<%# Bind("SupplierName") %>"> </asp:TextBox><br /> <asp:LinkButton ID="UpdateButton" runat="server" CausesValidation="True" CommandName="Update" Text="Update"> </asp:LinkButton> <asp:LinkButton ID="UpdateCancelButton" runat="server" CausesValidation="False" CommandName="Cancel" Text="Cancel"> </asp:LinkButton> </EditItemTemplate> <InsertItemTemplate> ... </InsertItemTemplate> <ItemTemplate> ... </ItemTemplate> </asp:FormView>

Ahora EditItemTemplate provocará que se inicie una excepción si se intenta usar. El problema es que los campos CategoryName y SupplierName se representan como controles web TextBox en EditItemTemplate. Será necesario cambiar estos controles TextBox por controles Label, o eliminarlos por completo. Simplemente se eliminarán por completo de EditItemTemplate.

En la figura 23 se muestra FormView en un explorador después de hacer clic en el botón Editar para Chai. Observe que los campos SupplierName y CategoryName que aparecen en ItemTemplate ya no están presentes, ya los acaba de eliminar de EditItemTemplate. Cuando se hace clic en el botón Actualizar, FormView continúa con la misma secuencia de pasos que los controles GridView y DetailsView.

By Default the EditItemTemplate Shows Each Editable Product Field as a TextBox or CheckBox

Figura 23: De forma predeterminada EditItemTemplate muestra cada campo editable del producto como un cuadro de texto o una casilla (Haga clic para ver la imagen a tamaño completo)

Cuando se hace clic en el botón Insertar, se produce el postback de ItemTemplate FormView. Pero no hay datos enlazados a FormView porque se agrega un nuevo registro. La interfaz InsertItemTemplate incluye los controles web para agregar un nuevo registro junto con los botones Insertar y Cancelar. El InsertItemTemplate generado de forma predeterminada por Visual Studio contiene un control TextBox para cada campo de valor no booleano y un control CheckBox para cada campo de valor booleano, de forma similar a la interfaz de EditItemTemplate autogenerada. Los controles TextBox tienen su propiedad Text enlazada al valor de su campo de datos correspondiente mediante enlace de datos bidireccional.

En el siguiente marcado declarativo se muestra el elemento InsertItemTemplate de FormView. Observe que se utiliza el método Bind() en la sintaxis de enlace de datos y que los controles web de los botones Insertar y Cancelar tienen sus propiedades CommandName establecidas en consecuencia.

<asp:FormView ID="FormView1" runat="server" DataKeyNames="ProductID" DataSourceID="ObjectDataSource1" AllowPaging="True"> <EditItemTemplate> ... </EditItemTemplate> <InsertItemTemplate> ProductName: <asp:TextBox ID="ProductNameTextBox" runat="server" Text="<%# Bind("ProductName") %>"> </asp:TextBox><br /> SupplierID: <asp:TextBox ID="SupplierIDTextBox" runat="server" Text="<%# Bind("SupplierID") %>"> </asp:TextBox><br /> CategoryID: <asp:TextBox ID="CategoryIDTextBox" runat="server" Text="<%# Bind("CategoryID") %>"> </asp:TextBox><br /> QuantityPerUnit: <asp:TextBox ID="QuantityPerUnitTextBox" runat="server" Text="<%# Bind("QuantityPerUnit") %>"> </asp:TextBox><br /> UnitPrice: <asp:TextBox ID="UnitPriceTextBox" runat="server" Text="<%# Bind("UnitPrice") %>"> </asp:TextBox><br /> UnitsInStock: <asp:TextBox ID="UnitsInStockTextBox" runat="server" Text="<%# Bind("UnitsInStock") %>"> </asp:TextBox><br /> UnitsOnOrder: <asp:TextBox ID="UnitsOnOrderTextBox" runat="server" Text="<%# Bind("UnitsOnOrder") %>"> </asp:TextBox><br /> ReorderLevel: <asp:TextBox ID="ReorderLevelTextBox" runat="server" Text="<%# Bind("ReorderLevel") %>"> </asp:TextBox><br /> Discontinued: <asp:CheckBox ID="DiscontinuedCheckBox" runat="server" Checked="<%# Bind("Discontinued") %>" /><br /> CategoryName: <asp:TextBox ID="CategoryNameTextBox" runat="server" Text="<%# Bind("CategoryName") %>"> </asp:TextBox><br /> SupplierName: <asp:TextBox ID="SupplierNameTextBox" runat="server" Text="<%# Bind("SupplierName") %>"> </asp:TextBox><br /> <asp:LinkButton ID="InsertButton" runat="server" CausesValidation="True" CommandName="Insert" Text="Insert"> </asp:LinkButton> <asp:LinkButton ID="InsertCancelButton" runat="server" CausesValidation="False" CommandName="Cancel" Text="Cancel"> </asp:LinkButton> </InsertItemTemplate> <ItemTemplate> ... </ItemTemplate> </asp:FormView>

Hay un matiz con la generación automática de InsertItemTemplate FormView. En concreto, los controles web TextBox se crean incluso para aquellos campos que son de solo lectura, como CategoryName y SupplierName. Al igual que con EditItemTemplate, es necesario quitar estos cuadros de texto de InsertItemTemplate.

En la figura 24 se muestra FormView en un explorador al agregar un nuevo producto, Acme Coffee. Observe que los campos SupplierName y CategoryName que aparecen en ItemTemplate ya no están presentes, pues se acaban de eliminar. Cuando se hace clic en el botón Insertar, FormView continúa con la misma secuencia de pasos que el control DetailsView, y agrega un nuevo registro a la tabla Products. En la figura 25 se muestran los detalles del producto Acme Coffee en FormView después de insertarlo.

The InsertItemTemplate Dictates the FormView's Inserting Interface

Figura 24: InsertItemTemplate determina la interfaz de inserción de FormView (Haga clic para ver la imagen a tamaño completo)

The Details for New Product, Acme Coffee, are Displayed in the FormView

Figura 25: Los detalles del nuevo producto, Acme Coffee, se muestran en FormView (Haga clic para ver la imagen a tamaño completo)

Al separar las interfaces de solo lectura, edición e inserción en tres plantillas independientes, FormView permite un mayor grado de control sobre estas interfaces que DetailsView y GridView.

Nota:

Al igual que DetailsView, la propiedad CurrentMode de FormView indica la interfaz que se muestra y su propiedad DefaultMode indica el modo al que vuelve FormView tras finalizar una edición o inserción.

Resumen

En este tutorial se han examinado los aspectos básicos de la inserción, edición y eliminación de datos mediante GridView, DetailsView y FormView. Los tres controles proporcionan cierto nivel de funcionalidades integradas de modificación de datos que se pueden usar sin escribir una sola línea de código en la página de ASP.NET gracias a los controles web de datos y ObjectDataSource. Pero las sencillas técnicas de apuntar y hacer clic dan lugar a una interfaz de usuario de modificación de datos bastante frágil e ingenua. Para proporcionar validación, insertar valores mediante programación, controlar las excepciones con elegancia, personalizar la interfaz de usuario, etc., tendrá que recurrir a muchas técnicas que se describirán en los próximos tutoriales.

¡Feliz programación!

Acerca del autor

Scott Mitchell, autor de siete libros de ASP y 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 a través de mitchell@4GuysFromRolla.com. o de su blog, que se puede encontrar en http://ScottOnWriting.NET.