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

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 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:

  1. GridView rellena los valores UpdateParameters de su instancia 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 el tutorial anterior)
  3. 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.

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

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

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.

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

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.

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

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.

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

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

Set the UnitPrice's DataFormatString and HtmlEncode Properties Accordingly

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.

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

Set the UnitPrice BoundField's ApplyFormatInEditMode property to 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.

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

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

A Label Has Been Added Above the GridView

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 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 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 o DeleteParameters, en función 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 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).

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

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)

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

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.

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

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

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 NULL asignados. Puede verlo si sigue estos 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 tabla de 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 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).

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 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 y ASP.NET, y fundador de 4GuysFromRolla.com, trabaja con tecnologías web de Microsoft desde 1998. Scott trabaja como consultor independiente, entrenador y escritor. Su último libro es Sams Teach Yourself ASP.NET 2.0 in 24 Hours. Puede ponerse en contacto con él a través de mitchell@4GuysFromRolla.com. o de su blog, que se puede encontrar en http://ScottOnWriting.NET.

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.