Información general sobre la inserción, actualización y eliminación de datos (C#)
por Scott Mitchell
En este tutorial veremos cómo asignar métodos Insert(), Update() y Delete() de ObjectDataSource a los métodos de las clases BLL, así como a configurar los controles GridView, DetailsView y FormView para proporcionar funcionalidades de modificación de datos.
Introducción
En los últimos tutoriales hemos examinado cómo mostrar datos en una página de 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 el uso de un control de origen de datos, como ObjectDataSource. Hemos visto cómo objectDataSource actúa como proxy entre la página ASP.NET y los datos subyacentes. Cuando un GridView necesita mostrar datos, invoca el método Select()
de ObjectDataSource, que a su vez invoca un método de nuestra Capa de Lógica Empresarial (BLL), que llama a un método del 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 cuando creamos los TableAdapters en la DAL en nuestro primer tutorial, Visual Studio agregó automáticamente métodos para insertar, actualizar y eliminar datos de la tabla de la base de datos subyacente. Además, en Creación de una capa de lógica empresarial diseñamos métodos en la BLL que llamaban a estos métodos DAL de modificación de datos.
Además de su método Select()
, el 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 configura 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()
del ObjectDataSource, que a su vez invocan a los métodos asociados del objeto subyacente (véase la figura 1).
Figura 1: Los métodos Insert()
, Update()
y Delete()
del ObjectDataSource sirven de proxy al BLL (Haga clic para ver la imagen a tamaño completo)
En este tutorial veremos cómo asignar los métodos Insert()
, Update()
y Delete()
del ObjectDataSource a métodos de clases de la BLL, así como cómo configurar los controles GridView, DetailsView y FormView para proporcionar capacidades de modificación de datos.
Paso 1: Crear las páginas web insertar, actualizar y eliminar tutoriales
Antes de empezar a explorar cómo insertar, actualizar y eliminar datos, primero se tardará un momento en crear las páginas de ASP.NET en nuestro proyecto de sitio web que necesitaremos para este tutorial y los siguientes varios. Empiece agregando una nueva carpeta denominada EditInsertDelete
. Después, agregue las siguientes páginas ASP.NET a esa carpeta, asegurándose 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
Figura 2: Agregar las páginas de 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 lo tanto, agregue este control de usuario a Default.aspx
arrastrándolo desde el Explorador de soluciones a la vista Diseño de la página.
Figura 3: Agregue el control de usuario SectionLevelTutorialListing.ascx
a Default.aspx
(haga clic aquí 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 tutoriales a través de un explorador. El menú de la izquierda ahora incluye elementos para la edición, inserción y eliminación de tutoriales.
Figura 4: El mapa del sitio incluye ahora entradas para los tutoriales de edición, inserción y eliminación
Paso 2: Agregar y configurar el control de ObjectDataSource
Dado que GridView, DetailsView y FormView difieren en sus funcionalidades y diseño de modificación de datos, vamos a examinar cada uno individualmente. En lugar de tener cada control con su propio ObjectDataSource, vamos a crear un único 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. Dado que la ProductsBLL
es la única clase BLL que proporciona métodos de edición, inserción y eliminación, configure el ObjectDataSource para que utilice esta clase.
Figura 5: Configurar ObjectDataSource para usar la clase ProductsBLL
(Haga clic para ver la imagen de tamaño completo)
En la siguiente pantalla podemos especificar qué métodos de la clase ProductsBLL
se asignan a las clases Select()
, Insert()
, Update()
y Delete()
del ObjectDataSource seleccionando la pestaña correspondiente y eligiendo el método en la lista desplegable. La figura 6, que ya debería resultarle familiar, asigna el método Select()
de ObjectDataSource al método GetProducts()
de la clase ProductsBLL
. Los métodos Insert()
, Update()
y Delete()
pueden configurarse seleccionando la pestaña correspondiente de la lista situada en la parte superior.
Figura 6: Hacer que el ObjectDataSource devuelva todos los productos (Haga clic para ver la imagen a tamaño completo)
Las figuras 7, 8 y 9 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.
Figura 7: Asignar el método Update()
del ObjectDataSource a la ProductBLL
de la clase UpdateProduct
(Haga clic para ver la imagen a tamaño completo)
Figura 8: Asignar el método Insert()
del ObjectDataSource a la ProductBLL
de la clase Agregar Product
(Haga clic para ver la imagen a tamaño completo)
Figura 9: Asignar el método Delete()
del ObjectDataSource a la ProductBLL
de la clase DeleteProduct
(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 a nuestro uso del DataObjectMethodAttribute
que decora los métodos del ProductsBLL
. Por ejemplo, el método DeleteProduct tiene la siguiente firma:
[System.ComponentModel.DataObjectMethodAttribute
(System.ComponentModel.DataObjectMethodType.Delete, true)]
public bool DeleteProduct(int productID)
{
...
}
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 omite estos atributos al crear las clases 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()
del ObjectDataSource, haga clic en Finalizar para completar el asistente.
Examen del marcado de ObjectDataSource
Después de configurar ObjectDataSource a través de 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 DeleteParameters
, UpdateParameters
y InsertParameters
que corresponden 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>
El 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 el ObjectDataSource está configurado para llamar a un método select que espera un parámetro de entrada (como GetProductsByCategoryID(categoryID)
). Como veremos 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, ya que analizaremos en un tutorial futuro.
Un efecto secundario de utilizar el asistente para configurar a 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 están editando 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. Analizaremos esta propiedad y su propósito con más detalle al explorar la simultaneidad optimista. Sin embargo, lo menciono ahora porque los métodos de nuestro BLL no esperan los valores originales y, por lo tanto, es importante que eliminemos 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, examinaremos esta propiedad y su utilidad en un futuro tutorial. 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 OldValuesParameterFormatString
de propiedad 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 lo tanto, quite la propiedad por completo de la sintaxis declarativa o, de la ventana Propiedades, establezca el valor en el valor predeterminado, {0}
.
Paso 3: Agregar un control web de datos y configurarlo para la modificación de datos
Una vez que objectDataSource se ha agregado a la página y configurado, estamos listos para agregar controles web de datos a la página para mostrar los datos y proporcionar un medio para que el usuario final lo modifique. Veremos 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 veremos en el resto de este artículo, agregar compatibilidad básica de edición, inserción y eliminación a través de los controles GridView, DetailsView y FormView es realmente tan sencillo como comprobar un par de casillas. Hay muchas sutilezas y casos perimetrales en el mundo real que hacen que proporcionar esa funcionalidad sea más implicada que simplemente apuntar y hacer clic. Sin embargo, este tutorial se centra únicamente en probar las funcionalidades de modificación de datos simplistas. Los tutoriales futuros examinarán las preocupaciones que sin duda surgirán en un entorno real.
Eliminar datos de GridView
Para empezar, arrastre un control GridView desde el cuadro de herramientas al Diseñador. A continuación, enlace ObjectDataSource a GridView seleccionándolo en la lista desplegable de la etiqueta inteligente de GridView. En este momento, el marcado declarativo de GridView será:
<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>
Enlazar GridView a ObjectDataSource a través de su etiqueta inteligente tiene dos ventajas:
- BoundFields y CheckBoxFields se crean automáticamente para cada uno de los campos devueltos por ObjectDataSource. Además, las propiedades BoundField y CheckBoxField se establecen en función de los metadatos del campo subyacente. Por ejemplo, los campos
ProductID
,CategoryName
ySupplierName
están marcados como de solo lectura en elProductsDataTable
y, por tanto, no deberían poder actualizarse durante la edición. Para ello, las propiedades ReadOnly de estos BoundFields se establecen entrue
. - La propiedad DataKeyNames se asigna al campo o campos de clave primaria 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. Para obtener más información sobre la propiedad
DataKeyNames
, consulte de nuevo el tutorial Maestro/Detalle Uso de una GridView maestra seleccionable con una DetailView de detalles.
Aunque GridView se puede vincular a ObjectDataSource a través de la ventana Propiedades o de la sintaxis declarativa, para hacerlo es necesario añadir manualmente las marcas BoundField y DataKeyNames
adecuadas.
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 una devolución de entrada y GridView realiza los pasos siguientes:
- Se asignan los valores
DeleteParameters
de ObjectDataSource - Se invoca el método
Delete()
del ObjectDataSource, eliminando el registro especificado - GridView se vuelve a vincular al ObjectDataSource invocando su método
Select()
Los valores asignados a los DeleteParameters
son los valores de los campos DataKeyNames
de la fila cuyo botón Eliminar se ha pulsado. Por lo tanto, es vital que la propiedad DataKeyNames
de un GridView esté correctamente configurada. Si falta, al DeleteParameters
se le asignará un valor null
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 del GridView, lo que significa que los valores DataKeys
se recordarán a través de postback incluso si el estado de vista de GridView se ha desactivado. Sin embargo, es muy importante que el estado de vista permanezca habilitado para GridViews que admite 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 concurrentes eliminando datos, existe la posibilidad de que estos usuarios concurrentes eliminen o editen accidentalmente registros que no tenían previsto.
Esta misma advertencia también se aplica a DetailsViews y FormViews.
Para agregar funcionalidades de eliminación a GridView, simplemente vaya a su etiqueta inteligente y active la casilla Habilitar eliminación.
Figura 10: Activar la casilla Habilitar eliminación
Al activar la casilla Habilitar eliminación de la etiqueta inteligente, se agrega un CommandField a 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 vimos el CommandField en acción con la selección de registros en el tutorial Maestro/Detalle Uso de una GridView maestra seleccionable con una DetailView de detalles.
El CommandField contiene una serie de propiedades ShowXButton
que indican qué serie de botones se muestran en el CommandField. Al marcar la casilla Habilitar eliminación se ha añadido un 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, ¡hemos terminado de añadir soporte de eliminación a GridView! Como se muestra en la figura 11, al visitar esta página a través de un explorador hay una columna de botones Eliminar.
Figura 11: CommandField agrega una columna de botones de eliminación (Haga clic para ver la imagen a tamaño completo)
Si ha creado este tutorial desde cero por su cuenta, al probar esta página al hacer clic en el botón Eliminar generará una excepción. Siga leyendo para obtener información sobre por qué se generaron estas excepciones y cómo corregirlas.
Nota:
Si sigue con la descarga que acompaña a este tutorial, estos problemas ya se han tenido en cuenta. Sin embargo, le recomendamos que lea los detalles que se enumeran a continuación para ayudar a identificar problemas que pueden surgir y soluciones alternativas adecuadas.
Si, al intentar eliminar un producto, obtiene 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
. DeleteProduct
, sin embargo, solo acepta un único parámetro de entrada, de ahí la excepción. Eliminar la propiedad OldValuesParameterFormatString
(o establecerla en {0}
) indica a ObjectDataSource que no intente pasar el parámetro de entrada original.
Figura 12: Asegurarse de que la propiedad OldValuesParameterFormatString
se ha borrado (Haga clic para ver la imagen a tamaño completo)
Aunque hubiera eliminado la propiedad OldValuesParameterFormatString
, seguirá obteniendo una excepción al intentar eliminar un producto con el mensaje "La instrucción DELETE entró 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
. Dado que cada producto de la base de datos Northwind tiene al menos un registro en Order Details
, no podemos eliminar ningún producto hasta que no eliminemos primero los registros de detalles del pedido asociados al producto.
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)
Para nuestro tutorial, vamos a eliminar todos los registros de la tabla Order Details
. En una aplicación real, tendríamos 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 el TableAdapter para incluir la eliminación de los detalles del pedido del producto especificado.
Vamos a eliminar 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. A continuación, en la ventana de consulta, ejecute la siguiente instrucción SQL: DELETE FROM [Order Details]
Figura 14: Eliminar todos los registros de la tabla Order Details
(Haga clic para ver la imagen a tamaño completo)
Tras vaciar 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 una devolución de entrada 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 futuro veremos 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, hacer clic en el botón Editar de una fila hace que esa fila se pueda editar, convirtiendo las celdas en cuadros de texto que contienen los valores existentes y reemplazando 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 el botón Cancelar para descartarlos. En cualquier caso, después de hacer clic en Actualizar o Cancelar GridView vuelve a su estado de edición previa.
Desde nuestra perspectiva como desarrollador de páginas, cuando el usuario final hace clic en el botón Editar de una fila determinada, se produce una devolución de postback y GridView realiza los pasos siguientes:
- La propiedad
EditItemIndex
de GridView se asigna al índice de la fila cuyo botón Editar se ha pulsado - GridView se vuelve a vincular al ObjectDataSource invocando su método
Select()
- El índice de la fila que coincide con el
EditItemIndex
se representa en "modo edición". En este modo, el botón Editar se sustituye por los botones Actualizar y Cancelar y los BoundFields cuyas propiedadesReadOnly
son False (el valor predeterminado) se renderizan como controles web TextBox cuyas propiedadesText
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:
- A los valores
UpdateParameters
de ObjectDataSource se les asignan los valores introducidos por el usuario final en la interfaz de edición de GridView - Se invoca el método
Update()
de ObjectDataSource, actualizando el registro especificado. - GridView se vuelve a vincular al ObjectDataSource invocando su método
Select()
Los valores de clave principal asignados al 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. Al igual que al eliminar, es vital que la propiedad DataKeyNames
de un GridView esté correctamente configurada. Si falta, al valor UpdateParameters
de la clave principal se le asignará un valor null
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 activando la casilla Habilitar edición en la etiqueta inteligente de GridView.
Figura 15: Activar la casilla Habilitar edición
Al marcar la casilla Habilitar edición se añadirá un CommandField (si es necesario) y se establecerá su propiedad ShowEditButton
en true
. Como vimos anteriormente, el CommandField contiene una serie de propiedades ShowXButton
que indican qué serie de botones se muestran en el CommandField. Al marcar la casilla Habilitar edición se añade la propiedad ShowEditButton
al 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>
Eso es todo lo que hay que hacer para agregar compatibilidad con la edición rudimentaria. Como muestra la Figura16, la interfaz de edición es bastante básica, cada BoundField cuya propiedad ReadOnly
se establece en false
(el valor predeterminado) se representa como un TextBox. Esto incluye campos como CategoryID
y SupplierID
, que son claves de otras tablas.
Figura 16: Al pulsar 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 introduce un
CategoryID
oSupplierID
que no existe en la base de datos, elUPDATE
violará una restricción de clave externa, provocando una excepción. - La interfaz de edición no incluye ninguna validación. Si no proporciona un valor requerido (como
ProductName
), o introduce un valor de cadena donde se espera un valor numérico (como introducir "¡Demasiado!" en la caja de textoUnitPrice
), se lanzará una excepción. En un tutorial futuro 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 GridView. Si elimináramos un campo de GridView, digamos
UnitPrice
, al actualizar los datos GridView no establecería el valorUnitPrice
UpdateParameters
, lo que cambiaría elUnitPrice
del registro de la base de datos a un valorNULL
. Del mismo modo, si se elimina de GridView un campo obligatorio, comoProductName
, la actualización fallará con la misma excepción "Column 'ProductName' does not allow nulls" mencionada anteriormente. - El formato de la interfaz de edición deja mucho que desear. El
UnitPrice
se muestra con cuatro decimales. Lo ideal sería que los valoresCategoryID
ySupplierID
contuvieran listas desplegables que enumeraran las categorías y los proveedores del sistema.
Estas son todas las deficiencias con las que tendremos que vivir por ahora, pero se abordarán en futuros tutoriales.
Inserción, edición y eliminación de datos con DetailsView
Como hemos 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 DetailsView como el flujo de trabajo desde el lado 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, comience agregando un DetailsView a la página Basics.aspx
por encima del GridView existente y vincúlelo al ObjectDataSource existente a través de la etiqueta inteligente de DetailsView. A continuación, elimine las propiedades Height
y Width
de DetailsView y active la opción Activar paginación de la etiqueta inteligente. Para habilitar la edición, inserción y eliminación de soporte técnico, simplemente active las casillas Habilitar edición, Habilitar inserción y Habilitar eliminación en la etiqueta inteligente.
Figura 17: Configurar DetailsView para admitir la edición, inserción y eliminación
Al igual que con GridView, agregar compatibilidad con edición, inserción o eliminación agrega un 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 CommandField aparece al final de la colección Columns de forma predeterminada. Dado que 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.
Figura 18: Configurar la vista detallada 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 DeleteParameters
de su ObjectDataSource basándose en los valores del DataKeyNames
; y completado con una llamada al método Delete()
de su 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 BoundFields cuya propiedad InsertVisible
esté ajustada a true
(el valor predeterminado). Aquellos campos de datos identificados como campos de autoincremento, como ProductID
, tienen su propiedad InsertVisible establecida en false
cuando se vincula el DetailsView al origen de datos a través de la etiqueta inteligente.
Al vincular un origen de datos a un DetailsView mediante la etiqueta inteligente, Visual Studio establece la propiedad InsertVisible
en false
solo para los campos de autoincremento. 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 a través de la sintaxis declarativa de DetailsView o a través del enlace Editar campos de la etiqueta inteligente. La figura 19 muestra el ajuste de las propiedades InsertVisible
a false
haciendo clic en el enlace Editar campos.
Figura 19: Northwind Traders ofrece ahora té Acme (Haga clic para ver la imagen a tamaño completo)
Tras configurar las propiedades InsertVisible
, visualice la página Basics.aspx
en un navegador y haga clic en el botón Nuevo. La figura 20 muestra la VistaDetalles al añadir una nueva bebida, Té Acme, a nuestra línea de productos.
Figura 20: Northwind Traders ofrece ahora té Acme (Haga clic para ver la imagen a tamaño completo)
Tras introducir los datos de Té Acme y hacer clic en el botón Insertar, se produce un postback y el nuevo registro se añade a la tabla de la base de datos Products
. Dado que en esta vista de detalles se enumeran los productos en orden con los que existen en la tabla de base de datos, debemos paginar al último producto para ver el nuevo producto.
Figura 21: Detalles para Té Acme (Haga clic para ver la imagen a tamaño completo)
Nota:
La propiedad CurrentMode de DetailsView indica la interfaz que se está mostrando y puede ser uno de los siguientes valores: Edit
, Insert
o ReadOnly
. La propiedad DefaultMode indica el modo al que vuelve el DetailsView una vez finalizada una edición o inserción y es útil para mostrar un 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 la vista DetailsView presentan las mismas limitaciones que la vista GridView: el usuario debe introducir los valores CategoryID
y SupplierID
existentes a través de 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 examinaremos para ampliar y mejorar la interfaz de edición de GridView en artículos futuros también se pueden aplicar a las interfaces de edición e inserción del control DetailsView.
Usar 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 dado que usa plantillas en lugar de campos, no hay ningún lugar para agregar BoundFields o CommandField usados por los controles GridView y DetailsView para proporcionar la interfaz de modificación de datos. En su lugar, esta interfaz de 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 a través de la lista desplegable de su etiqueta inteligente.
Para ilustrar estas técnicas, comience añadiendo un FormView a la página Basics.aspx
y, desde la etiqueta inteligente del FormView, enlácelo al ObjectDataSource ya creado. Esto generará un EditItemTemplate
, InsertItemTemplate
y ItemTemplate
para el FormView con controles web TextBox para recoger la entrada del usuario y controles web Botón para los botones Nuevo, Editar, Eliminar, Insertar, Actualizar y Cancelar. Además, la propiedad DataKeyNames
del FormView se establece en el campo de clave principal (ProductID
) del objeto devuelto por el 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 el ItemTemplate
del FormView después de que este haya sido enlazado a ObjectDataSource. De forma predeterminada, cada campo de producto de valor no booleano se vincula a la propiedad Text
de un control Web Label, mientras que cada campo de valor booleano (Discontinued
) se vincula 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 fijen 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>
La figura 22 muestra el ItemTemplate
de FormView visto a través de un explorador. Cada campo de producto aparece con los botones Nuevo, Editar y Eliminar de la parte inferior.
Figura 22: El formulario Defaut FormViewItemTemplate
Enumera cada campo del producto junto con los botones Nuevo, Editar y Eliminar (Haga clic para ver la imagen a tamaño completo)
Al igual que con GridView y DetailsView, al hacer clic en el botón Eliminar o en cualquier Botón, LinkButton o ImageButton cuya propiedad CommandName
esté establecida como Eliminar se produce un postback, se rellena el DeleteParameters
de ObjectDataSource basándose en el 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 al EditItemTemplate
, que se encarga de renderizar la interfaz de edición. Esta interfaz incluye los controles web para editar datos junto con los botones Actualizar y Cancelar. El EditItemTemplate
generado predeterminadamente por Visual Studio contiene una Etiqueta para cualquier campo de autoincremento (ProductID
), un TextBox para cada campo de valor no booleano y un CheckBox para cada campo de valor booleano. Este comportamiento es muy similar al de los BoundFields autogenerados en los controles GridView y DetailsView.
Nota:
Un pequeño problema con la autogeneración de EditItemTemplate
de FormView es que genera controles web TextBox para aquellos campos que son de solo lectura, como CategoryName
y SupplierName
. Veremos cómo tener en cuenta esto en breve.
Los controles TextBox del EditItemTemplate
tienen su propiedad Text
vinculada al valor de su campo de datos correspondiente utilizando databinding 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 del 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 corresponden a los campos de datos especificados mediante Bind()
se aplican al UpdateParameters
de ObjectDataSource. Alternativamente, la vinculación de datos unidireccional, denotada por <%# Eval("dataField") %>
, solo recupera los valores de los campos de datos cuando vincula datos a la plantilla y no devuelve los valores introducidos por el usuario a los parámetros de la fuente de datos en el postback.
El siguiente marcado declarativo muestra el EditItemTemplate
de FormView. Observe que aquí se utiliza el método Bind()
en la sintaxis de vinculación de datos y que los controles web de los botones Actualizar y Cancelar tienen sus propiedades CommandName
configuradas 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>
Nuestro EditItemTemplate
, en este punto, provocará que se lance una excepción si intentamos usarlo. El problema es que los campos CategoryName
y SupplierName
se renderizan como controles Web TextBox en EditItemTemplate
. Tenemos que cambiar estos TextBoxes por Etiquetas o eliminarlos por completo. Simplemente elimínelos 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 la ItemTemplate
ya no están presentes, pues acabamos de eliminarlos 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.
Figura 23: De forma predeterminada EditItemTemplate
muestra cada campo editable del producto como un cuadro de texto o una casilla de verificación (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
de FormView. Sin embargo, 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 TextBox para cada campo de valor no booleano y un CheckBox para cada campo de valor booleano, de forma similar a la interfaz del EditItemTemplate
autogenerado. Los controles TextBox tienen su propiedad Text
vinculada al valor de su campo de datos correspondiente utilizando databinding bidireccional.
El siguiente marcado declarativo muestra el InsertItemTemplate
de FormView. Observe que aquí se utiliza el método Bind()
en la sintaxis de vinculación de datos y que los controles web de los botones Insertar y Cancelar tienen sus propiedades CommandName
configuradas 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 una sutileza con la generación automática de InsertItemTemplate
de 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, Café Acme. Observe que los campos SupplierName
y CategoryName
que aparecen en ItemTemplate
ya no están presentes, pues acabamos de eliminarlos. Cuando se hace clic en el botón Insertar, FormView continúa con la misma secuencia de pasos que el control DetailsView, agregando un nuevo registro a la tabla Products
. En la figura 25 se muestran los detalles del producto Café Acme en FormView después de insertarlo.
Figura 24: El InsertItemTemplate
dicta la interfaz de inserción de FormView (Haga clic para ver la imagen a tamaño completo)
Figura 25: Los detalles del nuevo producto, Café Acme, 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 está mostrando y su propiedad DefaultMode
indica el modo al que vuelve FormView tras finalizar una edición o inserción.
Resumen
En este tutorial hemos 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 de modificación de datos integradas 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. Sin embargo, 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, inyectar valores programáticos, manejar con elegancia las excepciones, personalizar la interfaz de usuario, etc., tendremos que recurrir a un montón de técnicas que se discutirán en los próximos tutoriales.
¡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.
Comentarios
https://aka.ms/ContentUserFeedback.
Próximamente: A lo largo de 2024 iremos eliminando gradualmente GitHub Issues como mecanismo de comentarios sobre el contenido y lo sustituiremos por un nuevo sistema de comentarios. Para más información, vea:Enviar y ver comentarios de