Examinar los eventos relacionados con la inserción, actualización y eliminación (C#)
por Scott Mitchell
En este tutorial se examinará el uso de los eventos que se producen antes, durante y después de una operación de inserción, actualización o eliminación de un control web de datos de ASP.NET. También se verá cómo personalizar la interfaz de edición para actualizar solo un subconjunto de los campos del producto.
Introducción
Al usar las características integradas de inserción, edición o eliminación de los controles GridView, DetailsView o FormView, se muestra una variedad de pasos cuando el usuario final completa el proceso de agregar un nuevo registro o actualizar o eliminar un registro existente. Como se ha explicado en el tutorial anterior, cuando se edita una fila en GridView, el botón Editar se reemplaza por los botones Actualizar y Cancelar, y los controles BoundField se convierte en controles TextBox. Después de que el usuario final actualice los datos y haga clic en Actualizar, se realizan los pasos siguientes en postback:
- GridView rellena los valores
UpdateParameters
de su instancia de ObjectDataSource con los campos de identificación únicos del registro editado (mediante la propiedadDataKeyNames
) junto con los valores especificados por el usuario - GridView invoca el método
Update()
de ObjectDataSource, que a su vez invoca el método adecuado en el objeto subyacente (ProductsDAL.UpdateProduct
, en el tutorial anterior) - Los datos subyacentes, que ahora incluyen los cambios actualizados, se vuelven a enlazar al control GridView
Durante esta secuencia de pasos, se desencadenan varios eventos, lo que permite crear controladores de eventos para agregar lógica personalizada cuando sea necesario. Por ejemplo, antes del paso 1, se desencadena el evento RowUpdating
de GridView. En este momento, puede cancelar la solicitud de actualización si hay algún error de validación. Cuando se invoca el método Update()
, se desencadena el evento Updating
de ObjectDataSource, lo que proporciona la oportunidad de agregar o personalizar los valores de cualquiera de las instancias de UpdateParameters
. Una vez que se haya completado la ejecución del método del objeto subyacente de ObjectDataSource, se genera el evento Updated
de ObjectDataSource. Un controlador de eventos para el evento Updated
puede inspeccionar los detalles sobre la operación de actualización, como el número de filas afectadas y si se ha iniciado o no una excepción. Por último, después del paso 2, se desencadena el evento RowUpdated
de GridView; un controlador de eventos para este evento puede examinar información adicional sobre la operación de actualización que acaba de realizar.
En la figura 1 se muestra esta serie de eventos y pasos al actualizar GridView. El patrón de eventos de la figura 1 no es único para la actualización con GridView. La inserción, actualización o eliminación de datos desde controles GridView, DetailsView o FormView precipita la misma secuencia de eventos previos y posteriores para el control web de datos y ObjectDataSource.
Figura 1: Se desencadena una serie de eventos previos y posteriores al actualizar datos en un control GridView (Haga clic para ver la imagen a tamaño completo)
En este tutorial se examinará el uso de estos eventos para ampliar las funcionalidades integradas de inserción, actualización y eliminación de los controles web de datos de ASP.NET. También se verá cómo personalizar la interfaz de edición para actualizar solo un subconjunto de los campos del producto.
Paso 1: Actualización de los campos ProductName
y UnitPrice
de un producto
En las interfaces de edición del tutorial anterior, se tenían que incluir todos los campos de producto que no eran de solo lectura. Si se quitara un campo del control GridView (por ejemplo, QuantityPerUnit
) al actualizar los datos, el control web de datos no establecería el valor QuantityPerUnit
UpdateParameters
de ObjectDataSource. Después, ObjectDataSource pasaría un valor null
al método UpdateProduct
de la capa lógica de negocios (BLL), que cambiaría la columna QuantityPerUnit
del registro de base de datos editado a un valor NULL
. Del mismo modo, si se elimina un campo obligatorio de la interfaz de edición, como ProductName
, se producirá un error en la actualización con la excepción "Column 'ProductName' does not allow nulls". El motivo de este comportamiento es que ObjectDataSource se ha configurado para llamar al método UpdateProduct
de la clase ProductsBLL
, que esperaba un parámetro de entrada para cada uno de los campos de producto. Por tanto, la colección UpdateParameters
de ObjectDataSource contenía un parámetro para cada uno de los parámetros de entrada del método.
Si quiere proporcionar un control web de datos que permita al usuario final actualizar solo un subconjunto de campos, es necesario establecer mediante programación los valores UpdateParameters
que faltan en el controlador de eventos Updating
de ObjectDataSource, bien o crear y llamar a un método de la BLL que espera solo un subconjunto de los campos. Ahora se explorará este último enfoque.
En concreto, se creará una página que muestre solo los campos ProductName
y UnitPrice
en un control GridView editable. La interfaz de edición de este control GridView solo permitirá al usuario actualizar los dos campos mostrados, ProductName
y UnitPrice
. Como esta interfaz de edición solo proporciona un subconjunto de campos de un producto, es necesario crear una instancia ObjectDataSource que use el método UpdateProduct
de BLL existente y que tenga los valores de campo de producto que faltan establecidos mediante programación en su controlador de eventos Updating
, o bien crear un método BLL que espera solo el subconjunto de campos definidos en el control GridView. En este tutorial se usará la última opción y se creará una sobrecarga del método UpdateProduct
, que toma solo tres parámetros de entrada: productName
, unitPrice
y productID
:
[System.ComponentModel.DataObjectMethodAttribute
(System.ComponentModel.DataObjectMethodType.Update, false)]
public bool UpdateProduct(string productName, decimal? unitPrice, int productID)
{
Northwind.ProductsDataTable products = Adapter.GetProductByProductID(productID);
if (products.Count == 0)
// no matching record found, return false
return false;
Northwind.ProductsRow product = products[0];
product.ProductName = productName;
if (unitPrice == null) product.SetUnitPriceNull();
else product.UnitPrice = unitPrice.Value;
// Update the product record
int rowsAffected = Adapter.Update(product);
// Return true if precisely one row was updated, otherwise false
return rowsAffected == 1;
}
Al igual que el método UpdateProduct
original, esta sobrecarga comienza comprobando si hay un producto en la base de datos con el valor ProductID
especificado. Si no es así, devuelve false
, que indica que se ha producido un error en la solicitud para actualizar la información del producto. De lo contrario, actualiza los campos ProductName
y UnitPrice
del registro de producto existente en consecuencia y confirma la actualización llamando al método Update()
de TableAdapter, pasando la instancia ProductsRow
.
Con esta adición a la clase ProductsBLL
, ya puede crear la interfaz de GridView simplificada. Abra DataModificationEvents.aspx
en la carpeta EditInsertDelete
y agregue un control GridView a la página. Cree una instancia de ObjectDataSource y configúrela para usar la clase ProductsBLL
con la asignación del método Select()
a GetProducts
y la asignación del método Update()
a la sobrecarga UpdateProduct
que toma solo los parámetros de entrada productName
, unitPrice
y productID
. En la figura 2 se muestra el Asistente para Crear origen de datos al asignar el método Update()
de ObjectDataSource a la nueva sobrecarga del método UpdateProduct
de la clase ProductsBLL
.
Figura 2: Asignación del método Update()
de ObjectDataSource a la nueva sobrecarga de UpdateProduct
(Haga clic para ver la imagen a tamaño completo)
Como en el ejemplo solo se necesitará inicialmente la capacidad de editar datos, pero no de insertar o eliminar registros, dedique un momento a indicar explícitamente que los métodos Insert()
y Delete()
de ObjectDataSource no deben asignarse a ninguno de los métodos de la clase ProductsBLL
; para ello, vaya a las pestañas INSERT y DELETE, y elija (None) en la lista desplegable.
Figura 3: Selección de (None) en la lista desplegable para las pestañas INSERT y DELETE (Haga clic para ver la imagen a tamaño completo)
Después de completar este asistente, active la casilla Habilitar edición en la etiqueta inteligente de GridView.
Tras la finalización del Asistente para crear origen de datos y el enlace a GridView, Visual Studio ha creado la sintaxis declarativa para ambos controles. Vaya a la vista Origen para inspeccionar el marcado declarativo de ObjectDataSource, que se muestra a continuación:
<asp:ObjectDataSource ID="ObjectDataSource1" runat="server"
OldValuesParameterFormatString="original_{0}" SelectMethod="GetProducts"
TypeName="ProductsBLL" UpdateMethod="UpdateProduct">
<UpdateParameters>
<asp:Parameter Name="productName" Type="String" />
<asp:Parameter Name="unitPrice" Type="Decimal" />
<asp:Parameter Name="productID" Type="Int32" />
</UpdateParameters>
</asp:ObjectDataSource>
Como no hay asignaciones para los métodos Insert()
y Delete()
de ObjectDataSource, no hay ninguna sección InsertParameters
o DeleteParameters
. Además, como el método Update()
se asigna a la sobrecarga del método UpdateProduct
que solo acepta tres parámetros de entrada, la sección UpdateParameters
tiene solo tres instancias de Parameter
.
Tenga en cuenta que la propiedad OldValuesParameterFormatString
de ObjectDataSource está establecida en original_{0}
. Visual Studio establece automáticamente esta propiedad al usar el Asistente para configurar orígenes de datos. Pero como los métodos BLL no esperan que se pase el valor ProductID
original, quite esta asignación de propiedad por completo de la sintaxis declarativa de ObjectDataSource.
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. Por tanto, quite la propiedad por completo de la sintaxis declarativa o, en la ventana Propiedades, establezca el valor en el valor predeterminado, {0}
.
Aunque ObjectDataSource solo tiene UpdateParameters
para el nombre, el precio y el identificador del producto, Visual Studio ha agregado un control BoundField o CheckBoxField en GridView para cada uno de los campos del producto.
Figura 4: GridView contiene un control BoundField o CheckBoxField para cada uno de los campos del producto (Haga clic para ver la imagen a tamaño completo)
Cuando el usuario final edita un producto y hace clic en el botón Actualizar, GridView enumera los campos que no eran de solo lectura. Después, establece el valor del parámetro correspondiente en la colección UpdateParameters
de ObjectDataSource en el valor especificado por el usuario. Si no hay un parámetro correspondiente, GridView agrega uno a la colección. Por tanto, si GridView contiene controles BoundField y CheckBoxField para todos los campos del producto, ObjectDataSource terminará invocando la sobrecarga de UpdateProduct
que toma todos estos parámetros, a pesar de que el marcado declarativo de ObjectDataSource especifica solo tres parámetros de entrada (vea la figura 5). Del mismo modo, si hay alguna combinación de campos de producto que no son de solo lectura en GridView que no se corresponde con los parámetros de entrada de una sobrecarga de UpdateProduct
, se generará una excepción al intentar actualizar.
Figura 5: GridView agregará parámetros a la colección UpdateParameters
de ObjectDataSource (Haga clic para ver la imagen a tamaño completo)
Para asegurarse de que ObjectDataSource invoca la sobrecarga de UpdateProduct
que toma solo el nombre, el precio y el identificador del producto, es necesario restringir GridView para que solo tenga campos editables para ProductName
y UnitPrice
. Esto se puede lograr si se quitan los otros controles BoundField y CheckBoxField, y se establece la propiedad ReadOnly
de esos otros campos en true
, o mediante alguna combinación de los dos. Para este tutorial, simplemente se quitarán todos los campos de GridView excepto las campos instancias ProductName
y UnitPrice
de BoundField; después, el marcado declarativo de GridView tendrá el siguiente aspecto:
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False"
DataKeyNames="ProductID" DataSourceID="ObjectDataSource1">
<Columns>
<asp:CommandField ShowEditButton="True" />
<asp:BoundField DataField="ProductName"
HeaderText="ProductName" SortExpression="ProductName" />
<asp:BoundField DataField="UnitPrice" HeaderText="UnitPrice"
SortExpression="UnitPrice" />
</Columns>
</asp:GridView>
Aunque la sobrecarga de UpdateProduct
espera tres parámetros de entrada, solo hay dos instancias de BoundField en GridView. Esto se debe a que el parámetro de entrada productID
es un valor de clave principal y se pasa mediante el valor de la propiedad DataKeyNames
para la fila editada.
GridView, junto con la sobrecarga de UpdateProduct
, permite a un usuario editar solo el nombre y el precio de un producto sin perder ninguno de los demás campos del producto.
Figura 6: La interfaz permite editar solo el nombre y el precio del producto (Haga clic para ver la imagen a tamaño completo)
Nota:
Como se ha explicado en el tutorial anterior, es fundamental que el estado de visualización de GridView esté habilitado (el comportamiento predeterminado). Si establece la propiedad EnableViewState
de GridView en false
, corre el riesgo de que los usuarios simultáneos eliminen o editen registros accidentalmente.
Mejora del formato de UnitPrice
Aunque el ejemplo de GridView que se muestra en la figura 6 funciona, el campo UnitPrice
no tiene formato alguno, lo que da lugar a una presentación de precios que carece de símbolos de moneda y tiene cuatro posiciones decimales. Para aplicar un formato de moneda a las filas no editables, simplemente establezca la propiedad UnitPrice
de BoundField DataFormatString
en {0:c}
y su propiedad HtmlEncode
en false
.
Figura 7: Establecimiento de las propiedades DataFormatString
y HtmlEncode
de UnitPrice
adecuadamente (Haga clic para ver la imagen a tamaño completo)
Con este cambio, las filas no editables dan formato al precio como moneda; pero la fila editada sigue mostrando el valor sin el símbolo de moneda y con cuatro posiciones decimales.
Figura 8: Las filas no editables ahora tienen el formato de valores de moneda (Haga clic para ver la imagen a tamaño completo)
Las instrucciones de formato especificadas en la propiedad DataFormatString
se pueden aplicar a la interfaz de edición si se establece la propiedad ApplyFormatInEditMode
de BoundField en true
(el valor predeterminado es false
). Dedique un momento a establecer esta propiedad en true
.
Figura 9: Establecimiento de la propiedad UnitPrice
de Boundfield ApplyFormatInEditMode
en true
(Haga clic para ver la imagen a tamaño completo)
Con este cambio, el valor de UnitPrice
que se muestra en la fila editada también tiene el formato de moneda.
Figura 10: El valor de la fila editada UnitPrice
tiene ahora el formato de moneda (Haga clic para ver la imagen a tamaño completo)
Pero la actualización de un producto con el símbolo de moneda en el cuadro de texto como 19,00 $ inicia una excepción FormatException
. Cuando GridView intenta asignar los valores proporcionados por el usuario a la colección UpdateParameters
de ObjectDataSource, no puede convertir la cadena UnitPrice
"19,00 $" en la requerida por el parámetro decimal
(vea la figura 11). Para solucionar este problema, puede crear un controlador de eventos para el evento RowUpdating
de GridView y hacer que analice el valor UnitPrice
proporcionado por el usuario como un valor decimal
con formato de moneda.
El evento RowUpdating
de GridView acepta como segundo parámetro un objeto de tipo GridViewUpdateEventArgs, que incluye un diccionario NewValues
como una de sus propiedades que contiene los valores proporcionados por el usuario listos para asignarse a la colección UpdateParameters
de ObjectDataSource. Se puede sobrescribir el valor UnitPrice
existente en la colección NewValues
con un valor decimal analizado mediante el formato de moneda con las siguientes líneas de código en el controlador de eventos RowUpdating
:
protected void GridView1_RowUpdating(object sender, GridViewUpdateEventArgs e)
{
if (e.NewValues["UnitPrice"] != null)
e.NewValues["UnitPrice"] =
decimal.Parse(e.NewValues["UnitPrice"].ToString(),
System.Globalization.NumberStyles.Currency);
}
Si el usuario ha proporcionado un valor UnitPrice
(como "19,00 $"), este valor se sobrescribe con el valor decimal calculado por Decimal.Parse y el valor se analiza como una moneda. Esto analizará correctamente el decimal en caso de cualquier símbolo de moneda, comas, puntos decimales, etc., y usará la enumeración NumberStylesdel espacio de nombres System.Globalization.
En la figura 11 se muestra el problema causado por símbolos de moneda en el valor UnitPrice
proporcionado por el usuario, junto con cómo se puede usar el controlador de eventos RowUpdating
de GridView para analizar correctamente esa entrada.
Figura 11: El valorUnitPrice
de la fila editada tiene ahora el formato de moneda (Haga clic para ver la imagen a tamaño completo)
Paso 2: Prohibición de NULL UnitPrices
Aunque la base de datos está configurada para permitir valores NULL
en la columna Products
de la tabla UnitPrice
, es posible que quiera impedir que los usuarios que visitan esta página concreta especifiquen un valor NULL
UnitPrice
. Es decir, si un usuario no puede escribir un valor UnitPrice
al editar una fila de producto, en lugar de guardar los resultados en la base de datos, querrá mostrar un mensaje que informe al usuario de que, mediante esta página, los productos editados deben tener un precio especificado.
El objeto GridViewUpdateEventArgs
pasado al controlador de eventos RowUpdating
de GridView contiene una propiedad Cancel
que, si se establece en true
, finaliza el proceso de actualización. Ahora se ampliará el controlador de eventos RowUpdating
para establecer e.Cancel
y true
, y mostrar un mensaje que explique por qué el valor UnitPrice
de la colección NewValues
tiene un valor de null
.
Para empezar, agregue un control web Label a la página con el nombre MustProvideUnitPriceMessage
. Este control Label se mostrará si el usuario no puede especificar un valor UnitPrice
al actualizar un producto. Establezca la propiedad Text
de Label en "Debe proporcionar un precio para el producto". También se ha creado una clase CSS en Styles.css
denominada Warning
con la siguiente definición:
.Warning
{
color: Red;
font-style: italic;
font-weight: bold;
font-size: x-large;
}
Finalmente, establezca la propiedad CssClass
de la etiqueta en Warning
. En este momento, el Diseñador debe mostrar el mensaje de advertencia en rojo, negrita, cursiva y tamaño de fuente extra grande por encima de GridView, como se muestra en la figura 12.
Figura 12: Se ha agregado una etiqueta encima de GridView (Haga clic para ver la imagen a tamaño completo)
De manera predeterminada, este control Label debe estar oculto, por lo que debe establecer su propiedad Visible
en false
en el controlador de eventos Page_Load
:
protected void Page_Load(object sender, EventArgs e)
{
MustProvideUnitPriceMessage.Visible = false;
}
Si el usuario intenta actualizar un producto sin especificar UnitPrice
, se cancela la actualización y se muestra la etiqueta de advertencia. Aumente el controlador de eventos RowUpdating
de GridView de la siguiente manera:
protected void GridView1_RowUpdating(object sender, GridViewUpdateEventArgs e)
{
if (e.NewValues["UnitPrice"] != null)
{
e.NewValues["UnitPrice"] =
decimal.Parse(e.NewValues["UnitPrice"].ToString(),
System.Globalization.NumberStyles.Currency);
}
else
{
// Show the Label
MustProvideUnitPriceMessage.Visible = true;
// Cancel the update
e.Cancel = true;
}
}
Si un usuario intenta guardar un producto sin especificar un precio, se cancela la actualización y se muestra un mensaje útil. Aunque la base de datos (y la lógica de negocios) permite NULL
UnitPrice
, esta página ASP.NET particular no lo hace.
Figura 13: Un usuario no puede dejar UnitPrice
en blanco (Haga clic para ver la imagen a tamaño completo)
Hasta ahora ha visto cómo usar el evento RowUpdating
de GridView para modificar mediante programación los valores de parámetro asignados a la colección UpdateParameters
de ObjectDataSource, y cómo cancelar el proceso de actualización por completo. Estos conceptos se transfieren a los controles DetailsView y FormView, y también se aplican a la inserción y eliminación.
Estas tareas también se pueden realizar en el nivel de ObjectDataSource mediante controladores de eventos para sus eventos Inserting
, Updating
y Deleting
. Estos eventos se activan antes de que se invoque el método asociado del objeto subyacente y proporcionan una última oportunidad para modificar la colección de parámetros de entrada o cancelar la operación directamente. Los controladores de eventos de estos tres eventos se pasan a un objeto de tipo ObjectDataSourceMethodEventArgs que tiene dos propiedades de interés:
- Cancel, que, si se establece en
true
, cancela la operación que se realiza - InputParameters, que es la colección de
InsertParameters
,UpdateParameters
oDeleteParameters
, en función de si el controlador de eventos es para el eventoInserting
,Updating
oDeleting
Para ilustrar cómo trabajar con los valores de parámetro en el nivel de ObjectDataSource, se incluirá un elemento DetailsView en la página que permita a los usuarios agregar un nuevo producto. Este elemento DetailsView se usará a fin de proporcionar una interfaz para agregar rápidamente un nuevo producto a la base de datos. Para mantener una interfaz de usuario coherente al agregar un nuevo producto, se permitirá que el usuario solo escriba los valores de los campos ProductName
y UnitPrice
. De forma predeterminada, los valores que no se proporcionan en la interfaz de inserción de DetailsView se establecerán en un valor de base de datos NULL
. Pero se puede usar el evento Inserting
de ObjectDataSource para insertar valores predeterminados diferentes, como verá en breve.
Paso 3: Interfaz para agregar nuevos productos
Arrastre un control DetailsView desde el Cuadro de herramientas hasta el Diseñador encima de GridView, borre sus propiedades Height
y Width
, y vincúlelo a la instancia de ObjectDataSource ya presente en la página. Esto agregará un control BoundField o CheckBoxField para cada uno de los campos del producto. Como quiere usar esta vista de detalles para agregar nuevos productos, es necesario activar la opción Habilitar inserción desde la etiqueta inteligente; pero no hay ninguna opción de este tipo porque el método Insert()
de ObjectDataSource no está asignado a un método de la clase ProductsBLL
(recuerde que esta asignación se ha establecido en (None) al configurar el origen de datos, vea la figura 3).
Para configurar ObjectDataSource, seleccione el vínculo Configurar origen de datos en su etiqueta inteligente, para iniciar el asistente. La primera pantalla permite cambiar el objeto subyacente al que está enlazado ObjectDataSource; déjelo establecido en ProductsBLL
. En la siguiente pantalla se enumeran las asignaciones de los métodos de ObjectDataSource al objeto subyacente. Aunque ha indicado explícitamente que los métodos Insert()
y Delete()
no deben asignarse a ningún método, si va a las pestañas INSERT y DELETE, verá que hay una asignación. Esto se debe a que los métodos AddProduct
y DeleteProduct
de ProductsBLL
usan el atributo DataObjectMethodAttribute
para indicar que son los métodos predeterminados para Insert()
y Delete()
, respectivamente. Por tanto, el asistente para ObjectDataSource los selecciona cada vez que se ejecuta, a menos que se especifique otro valor explícitamente.
Deje el método Insert()
apuntado al método AddProduct
, pero vuelva a establecer la lista desplegable de la pestaña DELETE en (None).
Figura 14: Establecimiento de la lista desplegable de la pestaña INSERT en el método AddProduct
(Haga clic para ver la imagen a tamaño completo)
Figura 15: Establecimiento de la lista desplegable de la pestaña DELETE en el método (Haga clic para ver la imagen a tamaño completo)
Después de realizar estos cambios, la sintaxis declarativa de ObjectDataSource se expandirá para incluir una colección InsertParameters
, como se muestra a continuación:
<asp:ObjectDataSource ID="ObjectDataSource1" runat="server"
SelectMethod="GetProducts" TypeName="ProductsBLL"
UpdateMethod="UpdateProduct" OnUpdating="ObjectDataSource1_Updating"
InsertMethod="AddProduct" OldValuesParameterFormatString="original_{0}">
<UpdateParameters>
<asp:Parameter Name="productName" Type="String" />
<asp:Parameter Name="unitPrice" Type="Decimal" />
<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>
Al volver a ejecutar el asistente se ha agregado la propiedad OldValuesParameterFormatString
. Tómese un momento para borrar esta propiedad y establecerla en el valor predeterminado ({0}
), o bien quítela por completo de la sintaxis declarativa.
Con ObjectDataSource, que proporciona funcionalidades de inserción, la etiqueta inteligente de DetailsView incluirá ahora la casilla Habilitar inserción; vuelva al Diseñador y active esta opción. A continuación,reduzca el control DetailsView para que solo tenga dos controles BoundField, ProductName
y UnitPrice
, y CommandField. En este momento, la sintaxis declarativa de DetailsView debe ser similar a la siguiente:
<asp:DetailsView ID="DetailsView1" runat="server" AutoGenerateRows="False"
DataKeyNames="ProductID" DataSourceID="ObjectDataSource1">
<Fields>
<asp:BoundField DataField="ProductName"
HeaderText="ProductName" SortExpression="ProductName" />
<asp:BoundField DataField="UnitPrice" HeaderText="UnitPrice"
SortExpression="UnitPrice" />
<asp:CommandField ShowInsertButton="True" />
</Fields>
</asp:DetailsView>
En la figura 16 se muestra esta página vista desde un explorador en este punto. Como puede ver, DetailsView enumera el nombre y el precio del primer producto (Chai). Pero lo que quiere es una interfaz de inserción que proporcione un medio para que el usuario agregue rápidamente un nuevo producto a la base de datos.
Figura 16: DetailsView se representa actualmente en modo de solo lectura (Haga clic para ver la imagen a tamaño completo)
Para mostrar DetailsView en su modo de inserción, es necesario establecer la propiedad DefaultMode
en Inserting
. Esto representa DetailsView en modo de inserción cuando se visita por primera vez y se mantiene así después de insertar un nuevo registro. Como se muestra en la figura 17, este objeto DetailsView proporciona una interfaz rápida para agregar un nuevo registro.
Figura 17: DetailsView proporciona una interfaz para agregar rápidamente un nuevo producto (Haga clic para ver la imagen a tamaño completo)
Cuando el usuario escribe un nombre y un precio de producto (como "Acme Water" y 1,99, como en la figura 17) y hace clic en Insertar, se inicia un postback y comienza el flujo de trabajo de inserción, lo que culmina en un nuevo registro de producto que se agrega a la base de datos. DetailsView mantiene su interfaz de inserción y GridView se vuelve a enlazar automáticamente a su origen de datos para incluir el nuevo producto, como se muestra en la figura 18.
Figura 18: Se ha agregado el producto "Acme Water" a la base de datos
Aunque GridView no lo muestra en la figura 18, los campos de producto que carecen de la interfaz de DetailsView CategoryID
, SupplierID
, QuantityPerUnit
, etc. son valores de base de datos NULL
asignados. Puede verlo si sigue estos pasos:
- Vaya al Explorador de servidores en Visual Studio
- Expanda el nodo de base de datos
NORTHWND.MDF
- Haga clic con el botón derecho en el nodo de tabla de base de datos
Products
- Seleccione Mostrar datos de tabla
Esto enumerará todos los registros de la tabla Products
. Como se muestra en la figura 19, todas las columnas del nuevo producto que no sean ProductID
, ProductName
y UnitPrice
tienen valores NULL
.
Figura 19: Los campos de producto no proporcionados en DetailsView son valores NULL
asignados (Haga clic para ver la imagen a tamaño completo)
Es posible que quiera proporcionar un valor predeterminado distinto de NULL
para uno o varios de estos valores de columna, ya sea porque NULL
no es la mejor opción predeterminada o porque la propia columna de base de datos no permite NULL
. Para ello, puede establecer mediante programación los valores de los parámetros de la colección InputParameters
de DetailsView. Esta asignación se puede realizar en el controlador de eventos del evento ItemInserting
de DetailsView o en el evento Inserting
de ObjectDataSource. Como ya ha visto el uso de los eventos previos y posteriores en el nivel de control web de datos, esta vez se explorará el uso de los eventos de ObjectDataSource.
Paso 4: Asignación de valores a los parámetros CategoryID
y SupplierID
Para este tutorial, imagine que, para la aplicación, al agregar un nuevo producto desde esta interfaz se le debe asignar un valor CategoryID
y SupplierID
de 1. Como se ha mencionado antes, ObjectDataSource tiene un par de eventos previos y posteriores que se activan durante el proceso de modificación de datos. Cuando se invoca su método Insert()
, ObjectDataSource genera primero su evento Inserting
, luego llama al método al que se ha asignado su método Insert()
y, por último, genera el evento Inserted
. El controlador de eventos Inserting
ofrece una última oportunidad para ajustar los parámetros de entrada o cancelar la operación directamente.
Nota:
En una aplicación real, es probable que quiera permitir al usuario especificar la categoría y el proveedor, o elegir este valor en función de algunos criterios o lógica de negocios (en lugar de seleccionar a ciegas un identificador de 1). Independientemente, en el ejemplo se muestra cómo establecer mediante programación el valor de un parámetro de entrada del evento de nivel previo de ObjectDataSource.
Dedique un momento a crear un controlador de eventos para el evento Inserting
de ObjectDataSource. Observe que el segundo parámetro de entrada del controlador de eventos es un objeto de tipo ObjectDataSourceMethodEventArgs
, que tiene una propiedad par acceder a la colección de parámetros (InputParameters
) y una propiedad para cancelar la operación (Cancel
).
protected void ObjectDataSource1_Inserting
(object sender, ObjectDataSourceMethodEventArgs e)
{
}
En este momento, la propiedad InputParameters
contiene la colección InsertParameters
de ObjectDataSource con los valores asignados desde DetailsView. Para cambiar el valor de uno de estos parámetros, simplemente use: e.InputParameters["paramName"] = value
. Por tanto, para establecer los valores CategoryID
y SupplierID
en 1, ajuste el controlador de eventos Inserting
para que tenga un aspecto similar al siguiente:
protected void ObjectDataSource1_Inserting
(object sender, ObjectDataSourceMethodEventArgs e)
{
e.InputParameters["CategoryID"] = 1;
e.InputParameters["SupplierID"] = 1;
}
Esta vez cuando se agrega un nuevo producto (como Acme Soda), las columnas CategoryID
y SupplierID
del nuevo producto se establecen en 1 (véase la figura 20).
Figura 20: Los nuevos productos ahora tienen sus valores CategoryID
y SupplierID
establecidos en 1 (Haga clic para ver la imagen a tamaño completo)
Resumen
Durante el proceso de edición, inserción y eliminación, tanto el control web de datos como ObjectDataSource continúan por varios eventos previos y posteriores. En este tutorial se han examinado los eventos de nivel previo y ha visto cómo usarlos para personalizar los parámetros de entrada o cancelar la operación de modificación de datos por completo desde el control web de datos y los eventos de ObjectDataSource. En el siguiente tutorial, verá cómo crear y usar controladores de eventos para los eventos posteriores.
¡Feliz programación!
Acerca del autor
Scott Mitchell, autor de siete libros de ASP/ASP.NET y fundador de 4GuysFromRolla.com, ha trabajado con tecnologías web de Microsoft desde 1998. Scott trabaja como consultor independiente, entrenador y escritor. Su último libro es Sams Teach Yourself ASP.NET 2.0 in 24 Hours. Puede ponerse en contacto con él a través de mitchell@4GuysFromRolla.com. o de su blog, que se puede encontrar en http://ScottOnWriting.NET.
Agradecimientos especiales a
Esta serie de tutoriales fue revisada por muchos revisores. Los revisores principales de este tutorial fueron Jackie Goor y Liz Shulok. ¿Le interesaría revisar mis próximos artículos de MSDN? Si es así, escríbame a mitchell@4GuysFromRolla.com.