Examinar los eventos relacionados con la inserción, actualización y eliminación (VB)

por Scott Mitchell

Descargar PDF

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 realizan 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 explicó en el tutorial anterior, cuando se edita una fila en GridView, el botón Editar se reemplaza por los botones Actualizar y Cancelar y BoundFields se convierte en Cuadros de texto. Después de que el usuario final actualice los datos y haga clic en Actualizar, se realizan los pasos siguientes en postback:

  1. GridView rellena los UpdateParameters de ObjectDataSource con los campos de identificación únicos del registro editado (mediante la propiedad DataKeyNames) junto con los valores especificados por el usuario.
  2. GridView invoca el método Update() de ObjectDataSource, que a su vez invoca el método adecuado en el objeto subyacente (ProductsDAL.UpdateProduct, en nuestro tutorial anterior)
  3. Los datos subyacentes, que ahora incluyen los cambios actualizados, se vuelven a enlazar a GridView.

Durante esta secuencia de pasos, se desencadenan varios eventos, lo que nos 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, podemos 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 los 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 produjo 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 actualizar con GridView. La inserción, actualización o eliminación de datos de GridView, DetailsView o FormView precipita la misma secuencia de eventos previos y posteriores para el control web de datos y ObjectDataSource.

A Series of Pre- and Post-Events Fire When Updating Data in a GridView

Figura 1: Se desencadena una serie de eventos previos y posteriores al actualizar datos en GridView (haga clic para ver la imagen en tamaño completo)

En este tutorial examinaremos 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, todos los campos de producto que no eran de solo lectura tenían que incluirse. Si se quitara un campo de GridView (por ejemplo, QuantityPerUnit) al actualizar los datos, el control web de datos no establecería el valor QuantityPerUnitUpdateParameters de ObjectDataSource. A continuación, ObjectDataSource pasaría un valor de Nothing al método de capa lógica de negocios (BLL) de UpdateProduct, 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, la actualización fallará con la excepción "Column 'ProductName' does not allow nulls". El motivo de este comportamiento fue porque ObjectDataSource se configuró para llamar al método de la clase ProductsBLL, UpdateProduct, que esperaba un parámetro de entrada para cada uno de los campos de producto. Por lo 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 queremos 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 que faltan UpdateParameters en el controlador de eventos de Updating de ObjectDataSource o crear y llamar a un método BLL que espera solo un subconjunto de los campos. Vamos a explorar este último enfoque.

En concreto, vamos a crear una página que muestre solo los campos ProductName y UnitPrice en una GridView editable. Esta interfaz de edición de GridView solo permitirá al usuario actualizar los dos campos mostrados, ProductName y UnitPrice. Dado que esta interfaz de edición solo proporciona un subconjunto de campos de un producto, es necesario crear un ObjectDataSource que use el método de BLL existente UpdateProduct y que tenga los valores de campo de producto que faltan establecidos mediante programación en su controlador de eventos Updating o necesitamos crear un nuevo método BLL que espera solo el subconjunto de campos definidos en GridView. En este tutorial, vamos a usar la última opción y crear una sobrecarga del método UpdateProduct, una que toma solo tres parámetros de entrada: productName, unitPricey productID:

<System.ComponentModel.DataObjectMethodAttribute _
    (System.ComponentModel.DataObjectMethodType.Update, False)> _
    Public Function UpdateProduct(productName As String, _
        unitPrice As Nullable(Of Decimal), productID As Integer) _
        As Boolean

    Dim products As Northwind.ProductsDataTable = _
        Adapter.GetProductByProductID(productID)

    If products.Count = 0 Then
        Return False
    End If

    Dim product As Northwind.ProductsRow = products(0)

    product.ProductName = productName
    If Not unitPrice.HasValue Then
        product.SetUnitPriceNull()
    Else
        product.UnitPrice = unitPrice.Value
    End If

    Dim rowsAffected As Integer = Adapter.Update(product)

    Return rowsAffected = 1
End Function

Al igual que el método original UpdateProduct, esta sobrecarga comienza comprobando si hay un producto en la base de datos con el ProductID especificado. Si no es así, devuelve False, que indica que se produjo 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 nuestra clase ProductsBLL, estamos listos para crear la interfaz GridView simplificada. Abra DataModificationEvents.aspx en la carpeta EditInsertDelete y agregue GridView a la página. Cree un nuevo ObjectDataSource y configúrelo para usar la clase ProductsBLL con su asignación de método Select() a GetProducts y su asignación de 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 de la clase ProductsBLL, UpdateProduct.

Map the ObjectDataSource's Update() Method to the New UpdateProduct Overload

Figura 2: Asignar el método Update() del ObjectDataSource a la sobrecarga UpdateProduct nueva (Haga clic para ver la imagen a tamaño completo)

Dado que nuestro ejemplo solo necesitará inicialmente la capacidad de editar datos, pero no para 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 (Ninguno) en la lista desplegable.

Choose (None) From the Drop-Down List for the INSERT and DELETE Tabs

Figura 3: Seleccionar (Ninguno) en la lista desplegable para las pestañas INSERT y DELETE (Haga clic para ver la imagen de 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>

Puesto que no hay asignaciones para los métodos Insert() y Delete() de ObjectDataSource, no hay ninguna sección InsertParameters o DeleteParameters. Además, dado que 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 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. Sin embargo, dado que nuestros métodos BLL no esperan que se pase el valor original ProductID, 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 lo 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 BoundField o CheckBoxField en GridView para cada uno de los campos del producto.

The GridView Contains a BoundField or CheckBoxField for Each of the Product's Fields

Figura 4: GridView contiene un BoundField o CheckBoxField para cada uno de los campos del producto (Haga clic para ver la imagen en 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. A continuación, establece el valor del parámetro correspondiente en la colecciónUpdateParameters de ObjectDataSource en el valor especificado por el usuario. Si no hay un parámetro correspondiente, GridView agrega uno a la colección. Por lo tanto, si GridView contiene BoundFields y CheckBoxFields para todos los campos del producto, ObjectDataSource terminará invocando la sobrecarga 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 UpdateProduct, se generará una excepción al intentar actualizar.

The GridView Will Add Parameters to the ObjectDataSource's UpdateParameters Collection

Figura 5: GridView agregará parámetros a la colección UpdateParameters de ObjectDataSource (haga clic para ver la imagen en tamaño completo)

Para asegurarse de que ObjectDataSource invoca la sobrecarga UpdateProduct que toma solo el nombre, el precio y el identificador del producto, es necesario restringir GridView para que solo tenga campos editables de ProductName y UnitPrice. Esto se puede lograr quitando los otros BoundFields y CheckBoxFields, estableciendo la propiedad ReadOnly de esos otros campos en True, o mediante alguna combinación de los dos. Para este tutorial, vamos a simplemente quitar todos los campos GridView excepto los campos ProductName y UnitPrice BoundFields, después de los cuales 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 UpdateProduct espera tres parámetros de entrada, solo tenemos dos BoundFields en GridView. Esto se debe a que el parámetro de entrada productID es un valor de clave principal y se pasa a través del valor de la propiedad DataKeyNames para la fila editada.

GridView, junto con la sobrecarga 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.

The Interface Allows Editing Just the Product's Name and Price

Figura 6: La interfaz permite editar solo el nombre y el precio del producto (haga clic para ver la imagen en tamaño completo)

Nota:

Como se explicó en el tutorial anterior, es fundamental que el estado de vista 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 representación de precios que carece de símbolos de moneda y tiene cuatro posiciones decimales. Para aplicar un formato de moneda para las filas no editables, simplemente establezca la propiedad UnitPrice de BoundField DataFormatString en {0:c} y su propiedad HtmlEncode en False.

Set the UnitPrice's DataFormatString and HtmlEncode Properties Accordingly

Figura 7: Establecer las propiedades de UnitPrice, DataFormatString y HtmlEncode adecuadamente (haga clic aquí para ver la imagen en tamaño completo)

Con este cambio, las filas no editables dan formato al precio como moneda; sin embargo, la fila editada sigue mostrando el valor sin el símbolo de moneda y con cuatro posiciones decimales.

The Non-Editable Rows are Now Formatted as Currency Values

Figura 8: Las filas no editables ahora tienen el formato de valores de moneda (haga clic para ver la imagen en tamaño completo)

Las instrucciones de formato especificadas en la propiedad DataFormatString se pueden aplicar a la interfaz de edición estableciendo la propiedad ApplyFormatInEditMode de BoundField en True (el valor predeterminado es False). Dedique un momento a establecer esta propiedad en True.

Set the UnitPrice BoundField's ApplyFormatInEditMode property to True

Figura 9: establezca 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.

Screenshot of the GridView showing the edited row's UnitPrice value formatted as a currency.

Figura 10: El valor de la fila editada UnitPrice tiene ahora el formato de moneda (haga clic para ver la imagen en tamaño completo)

Sin embargo, la actualización de un producto con el símbolo de moneda en el cuadro de texto como 19,00 $ produce un 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, podemos crear un controlador de eventos para el evento RowUpdating de GridView y hacer que analice el proporcionado por el usuario UnitPrice como un formato de moneda Decimal.

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. Podemos sobrescribir el valor existente UnitPrice 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 Sub GridView1_RowUpdating(sender As Object, e As GridViewUpdateEventArgs) _
    Handles GridView1.RowUpdating
    If e.NewValues("UnitPrice") IsNot Nothing Then
        e.NewValues("UnitPrice") = _
            Decimal.Parse(e.NewValues("UnitPrice").ToString(), _
                System.Globalization.NumberStyles.Currency)
    End If
End Sub

Si el usuario ha proporcionado un valor UnitPrice (como "19,00 $"), este valor se sobrescribe con el valor decimal calculado por Decimal.Parse, analizando el valor 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 NumberStyles en el espacio de nombres System.Globalization.

En la figura 11 se muestra el problema causado por símbolos de moneda en el UnitPrice proporcionado por el usuario, junto con cómo se puede usar el controlador de eventos RowUpdating de GridView para analizar correctamente dicha entrada.

Diagram showing how the ObjectDataSource processes the UnitPrice field and how the RowUpdate event handler of the GridView converts a string to a decimal.

Figura 11: El valor de la fila editada UnitPrice tiene ahora el formato de moneda (haga clic para ver la imagen en tamaño completo)

Paso 2: ProhibirNULL UnitPrices

Aunque la base de datos está configurada para permitir valores NULL en la columna Products de la tabla UnitPrice, es posible que queramos impedir que los usuarios visiten esta página concreta especificando un valor NULLUnitPrice. 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, queremos 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 de GridView RowUpdating contiene una propiedad Cancel que, si se establece en True, finaliza el proceso de actualización. Vamos a extender 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 Nothing.

Empiece agregando un control web Label a la página denominada MustProvideUnitPriceMessage. Este control Label se mostrará si el usuario no puede especificar un valor UnitPrice al actualizar un producto. Establezca la propiedad Label de Text en "Debe proporcionar un precio para el producto". También he creado una nueva 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, tamaño de fuente adicional grande por encima de GridView, como se muestra en la figura 12.

A Label Has Been Added Above the GridView

Figura 12: Se ha agregado una etiqueta encima de GridView (haga clic para ver la imagen en tamaño completo)

De forma predeterminada, esta Label debe estar oculta, por lo que debe establecer su propiedad Visible en False en el controlador de eventos Page_Load:

Protected Sub Page_Load(sender As Object, e As System.EventArgs) Handles Me.Load
    MustProvideUnitPriceMessage.Visible = False
End Sub

Si el usuario intenta actualizar un producto sin especificar UnitPrice, queremos cancelar la actualización y mostrar la etiqueta de advertencia. Aumente el controlador de eventos RowUpdating de GridView de la siguiente manera:

Protected Sub GridView1_RowUpdating(sender As Object, e As GridViewUpdateEventArgs) _
    Handles GridView1.RowUpdating

    If e.NewValues("UnitPrice") IsNot Nothing Then
        e.NewValues("UnitPrice") = _
            Decimal.Parse(e.NewValues("UnitPrice").ToString(), _
                System.Globalization.NumberStyles.Currency)
    Else
        MustProvideUnitPriceMessage.Visible = True

        e.Cancel = True
    End If
End Sub

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 NULLUnitPrice, esta página ASP.NET particular no lo hace.

A User Cannot Leave UnitPrice Blank

Figura 13: Un usuario no puede dejar UnitPrice en blanco (haga clic para ver la imagen en tamaño completo)

Hasta ahora hemos 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, así como 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 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 proporcionen 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 está realizando.
  • InputParameters, que es la colección de InsertParameters, UpdateParameters o DeleteParameters, dependiendo de si el controlador de eventos es para el evento Inserting, Updating o Deleting.

Para ilustrar cómo trabajar con los valores de parámetro en el nivel ObjectDataSource, vamos a incluir un DetailsView en nuestra página que permita a los usuarios agregar un nuevo producto. Este DetailsView se usará para 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, vamos a 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. Sin embargo, podemos usar el evento ObjectDataSource Inserting para insertar valores predeterminados diferentes, como veremos en breve.

Paso 3: Proporcionar una interfaz para agregar nuevos productos

Arrastre un control DetailsView desde el Cuadro de herramientas hasta el Diseñador situado encima de GridView, borre sus propiedades Height y Width y vincúlelo a ObjectDataSource ya presente en la página. Esto agregará un BoundField o CheckBoxField para cada uno de los campos del producto. Puesto que queremos usar esta vista de detalles para agregar nuevos productos, es necesario comprobar la opción Habilitar inserción desde la etiqueta inteligente; sin embargo, 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 establecemos esta asignación 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, iniciando 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 hemos 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 allí. Esto se debe a que los métodos de ProductsBLL, AddProduct y DeleteProduct, usan el atributo DataObjectMethodAttribute para indicar que son los métodos predeterminados para Insert() y Delete(), respectivamente. Por lo tanto, el asistente ObjectDataSource los selecciona cada vez que ejecuta el asistente a menos que se especifique algún otro valor explícitamente.

Deje el método Insert() que apunta al método AddProduct, pero vuelva a establecer la lista desplegable de la pestaña DELETE en (None).

Set the INSERT Tab's Drop-Down List to the AddProduct Method

Figura 14: Establecer la lista desplegable de la pestaña INSERT en el método AddProduct (haga clic para ver la imagen en tamaño completo)

Set the DELETE Tab's Drop-Down List to (None)

Figura 15: Establecer la lista desplegable de la pestaña DELETE en el método (haga clic para ver la imagen en 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>

Volver a ejecutar el asistente agregó la propiedad OldValuesParameterFormatString. Tómese un momento para borrar esta propiedad estableciendo esta propiedad en el valor predeterminado ({0}) o quitándola por completo de la sintaxis declarativa.

Con ObjectDataSource, que proporciona funcionalidades de inserción, la etiqueta inteligente DetailsView incluirá ahora la casilla Habilitar inserción; vuelva al Diseñador y active esta opción. A continuación,pare el control DetailsView para que solo tenga dos BoundFields: ProductName y UnitPrice y CommandField. En este momento, la sintaxis declarativa de DetailsView debe tener el aspecto:

<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). Sin embargo, lo que queremos 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.

The DetailsView is Currently Rendered in Read-Only Mode

Figura 16: DetailsView se representa actualmente en modo de solo lectura (haga clic para ver la imagen en 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 lo mantiene allí 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.

The DetailsView Provides an Interface for Quickly Adding a New Product

Figura 17: DetailsView proporciona una interfaz para agregar rápidamente un nuevo producto (haga clic para ver la imagen en 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.

The Product

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 asignados NULL. Puede verlo realizando los siguientes pasos:

  1. Vaya al Explorador de servidores en Visual Studio.
  2. Expanda el nodo de base de datos NORTHWND.MDF.
  3. Haga clic con el botón derecho en el nodo de la base de datos Products.
  4. 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.

The Product Fields Not Provided in the DetailsView are Assigned NULL Values

Figura 19: Los campos de producto no proporcionados en DetailsView son valores asignados NULL (haga clic para ver la imagen en 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, podemos 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. Dado que ya hemos visto el uso de los eventos previos y posteriores en el nivel de control web de datos, vamos a explorar el uso de los eventos de ObjectDataSource esta vez.

Paso 4: Asignar valores a los parámetros CategoryID y SupplierID

Para este tutorial, imaginemos que para nuestra aplicación al agregar un nuevo producto a través de esta interfaz se le debe asignar un valor CategoryID y SupplierID de 1. Como se mencionó anteriormente, 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 nos 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 por ellos en función de algunos criterios o lógica de negocios (en lugar de seleccionar ciegamente un identificador de 1). Independientemente, el ejemplo 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 para tener acceso a la colección de parámetros (InputParameters) y una propiedad para cancelar la operación (Cancel).

Protected Sub ObjectDataSource1_Inserting _
    (sender As Object, e As ObjectDataSourceMethodEventArgs) _
    Handles ObjectDataSource1.Inserting

End Sub

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 lo 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 Sub ObjectDataSource1_Inserting _
    (sender As Object, e As ObjectDataSourceMethodEventArgs) _
    Handles ObjectDataSource1.Inserting

    e.InputParameters("CategoryID") = 1
    e.InputParameters("SupplierID") = 1
End Sub

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

New Products Now Have Their CategoryID and SupplierID Values Set to 1

Figura 20: Los nuevos productos ahora tienen sus valores CategoryID y SupplierID establecidos en 1 (haga clic para ver la imagen en tamaño completo)

Resumen

Durante el proceso de edición, inserción y eliminación, tanto el control web de datos como el ObjectDataSource continúan a través de varios eventos previos y posteriores. En este tutorial hemos examinado los eventos de nivel previo y hemos 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 veremos 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 contó con la revisión de muchos revisores que fueron de gran ayuda. Los revisores principales de este tutorial fueron Zack Jones y Liz Shulok. ¿Le interesaría revisar mis próximos artículos de MSDN? Si fuera así, escríbame a mitchell@4GuysFromRolla.com.