Interactuar con la página de contenido desde la página maestra (C#)

por Scott Mitchell

Examina cómo llamar a métodos, establecer propiedades, etc. de la página de contenido desde el código de la página maestra.

Introducción

En el tutorial anterior se ha examinado cómo hacer que la página de contenido interactúe mediante programación con su página maestra. Recuerde que hemos actualizado la página maestra para incluir un control GridView que enumera los cinco productos agregados más recientemente. A continuación, creamos una página de contenido a partir de la cual el usuario podría agregar un nuevo producto. Al agregar un nuevo producto, la página de contenido necesaria para indicar a la página maestra que actualice su GridView para que incluya el producto recién agregado. Esta funcionalidad se ha realizado agregando un método público a la página maestra que actualizó los datos enlazados a GridView y, a continuación, invocando ese método desde la página de contenido.

La forma más común de interacción de contenido y página maestra se origina en la página de contenido. Sin embargo, es posible que la página maestra enrute la página de contenido actual en acción y es posible que dicha funcionalidad sea necesaria si la página maestra contiene elementos de la interfaz de usuario que permiten a los usuarios modificar los datos que también se muestran en la página de contenido. Considere una página de contenido que muestre la información de productos en un control GridView y una página maestra que incluya un control Button que, cuando se hace clic, duplica los precios de todos los productos. Al igual que en el ejemplo del tutorial anterior, GridView debe actualizarse después de hacer clic en el botón de precio doble para que muestre los nuevos precios, pero en este escenario es la página maestra que necesita enrutar la página de contenido a la acción.

En este tutorial se explora cómo tener la funcionalidad de invocación de página maestra definida en la página de contenido.

Instigar la interacción mediante programación a través de un controlador de eventos y eventos

Invocar la funcionalidad de la página de contenido desde una página maestra es más difícil que lo contrario. Dado que una página de contenido tiene una sola página maestra, al instigar la interacción mediante programación desde la página de contenido sabemos qué métodos y propiedades públicos están a nuestra disposición. Sin embargo, una página maestra puede tener muchas páginas de contenido diferentes, cada una con su propio conjunto de propiedades y métodos. ¿Cómo, entonces, podemos escribir código en la página maestra para realizar alguna acción en su página de contenido cuando no sepamos qué página de contenido se invocará hasta el tiempo de ejecución?

Considere una ASP.NET control Web, como el control Botón. Un control Button puede aparecer en cualquier número de páginas de ASP.NET y necesita un mecanismo por el que puede alertar a la página en la que se ha realizado clic. Esto se logra mediante eventos. En concreto, el control Botón genera su Click evento cuando se hace clic en él; la página de ASP.NET que contiene el botón puede responder opcionalmente a esa notificación a través de un controladorde eventos.

Este mismo patrón se puede usar para tener una funcionalidad de desencadenador de página maestra en sus páginas de contenido:

  1. Agregue un evento a la página maestra.
  2. Genere el evento cada vez que la página maestra necesite comunicarse con su página de contenido. Por ejemplo, si la página maestra necesita alertar de su página de contenido que el usuario ha duplicado los precios, su evento se generará inmediatamente después de que se hayan duplicado los precios.
  3. Cree un controlador de eventos en esas páginas de contenido que necesiten realizar alguna acción.

Este resto de este tutorial implementa el ejemplo descrito en la Introducción; es decir, una página de contenido que enumera los productos de la base de datos y una página maestra que incluye un control Button para duplicar los precios.

Paso 1: Mostrar productos en una página de contenido

Nuestro primer orden de negocio es crear una página de contenido que muestre los productos de la base de datos Northwind. (Hemos agregado la base de datos Northwind al proyecto en el tutorial anterior, Interactuar con la página maestra desde la página de contenido). Comience agregando una nueva página de ASP.NET a la ~/Admin carpeta denominada Products.aspx, asegurándose de enlazarla a la Site.master página maestra. En la figura 1 se muestra el Explorador de soluciones después de agregar esta página al sitio web.

Add a New ASP.NET Page to the Admin Folder

Figura 01: Agregar una nueva página de ASP.NET a la Admin carpeta (haga clic para ver la imagen de tamaño completo)

Recuerde que, en el tutorial Especificar el título, las etiquetas meta y otros encabezados HTML del tutorial página maestra, creamos una clase de página base personalizada denominada BasePage que genera el título de la página si no se establece explícitamente. Vaya a la clase de código subyacente de la Products.aspx página y haga que derive de BasePage (en lugar de System.Web.UI.Page).

Actualice el archivo Web.sitemap para incluir una entrada para esta lección. Agregue el siguiente marcado debajo de para <siteMapNode> la lección De interacción de contenido a página maestra:

<siteMapNode url="~/Admin/Products.aspx" title="Master to Content Page Interaction" />

La adición de este <siteMapNode> elemento se refleja en la lista Lecciones (vea la figura 5).

Vuelva a Products.aspx. En el control Content para MainContent, agregue un control GridView y asígnele ProductsGridel nombre. Enlace GridView a un nuevo control SqlDataSource denominado ProductsDataSource.

Bind the GridView to a New SqlDataSource Control

Figura 02: Enlazar GridView a un nuevo control SqlDataSource (haga clic para ver la imagende tamaño completo)

Configure el asistente para que use la base de datos Northwind. Si ha trabajado en el tutorial anterior, ya debería tener una cadena de conexión denominada NorthwindConnectionString en Web.config. Elija esta cadena de conexión en la lista desplegable, como se muestra en la figura 3.

Configure the SqlDataSource to Use the Northwind Database

Figura 03: Configurar SqlDataSource para usar la base de datos Northwind (haga clic para ver la imagende tamaño completo)

A continuación, especifique la instrucción del control de SELECT origen de datos eligiendo la tabla Products en la lista desplegable y devolviendo las columnas ProductName y UnitPrice (consulte la figura 4). Haga clic en Siguiente y, a continuación, en Finalizar para completar el Asistente para configurar orígenes de datos.

Return the ProductName and UnitPrice Fields from the Products Table

Figura 04: Devolver los campos ProductName y UnitPrice de la tabla Products(haga clic para ver la imagen de tamaño completo)

Eso es todo. Después de completar el asistente, Visual Studio agrega dos BoundFields a GridView para reflejar los dos campos devueltos por el control SqlDataSource. A continuación se muestra el marcado de los controles GridView y SqlDataSource. En la ilustración 5 se muestra la página cuando se ve a través de un explorador.

<asp:GridView ID="ProductsGrid" runat="server" AutoGenerateColumns="False" 
 DataSourceID="ProductsDataSource">
 <Columns>
 <asp:BoundField DataField="ProductName" HeaderText="ProductName" 
 SortExpression="ProductName" />
 <asp:BoundField DataField="UnitPrice" HeaderText="UnitPrice" 
 SortExpression="UnitPrice" />
 </Columns>
</asp:GridView>

<asp:SqlDataSource ID="ProductsDataSource" runat="server" 
 ConnectionString="<%$ ConnectionStrings:NorthwindConnectionString %>" 
 SelectCommand="SELECT [ProductName], [UnitPrice] FROM [Products]">
</asp:SqlDataSource>

Each Product and its Price is Listed in the GridView

Figura 05: Cada producto y su precio se muestran en GridView (haga clic para ver la imagen de tamaño completo)

Nota:

No dude en limpiar la apariencia de GridView. Algunas sugerencias incluyen dar formato al valor UnitPrice mostrado como moneda y usar colores y fuentes de fondo para mejorar la apariencia de la cuadrícula. Para obtener más información sobre cómo mostrar y dar formato a los datos en ASP.NET, consulte mi serie de tutoriales Trabajar con datos.

Paso 2: Agregar un botón de precios dobles a la página maestra

Nuestra siguiente tarea consiste en agregar un control Web button a la página maestra que, cuando se hace clic, duplicará el precio de todos los productos de la base de datos. Abra la Site.master página maestra y arrastre un botón desde el cuadro de herramientas al Diseñador, colocándolo debajo del RecentProductsDataSource control SqlDataSource que hemos agregado en el tutorial anterior. Establezca la propiedad de button ID en DoublePrice y su propiedad Text en "Double Product Prices".

A continuación, agregue un control SqlDataSource a la página maestra y asígnele el nombre DoublePricesDataSource. SqlDataSource se usará para ejecutar la UPDATE instrucción para duplicar todos los precios. En concreto, es necesario establecer sus ConnectionString propiedades y UpdateCommand en la cadena de conexión y UPDATE la instrucción adecuadas. A continuación, es necesario llamar al método del Update control SqlDataSource cuando se hace clic en el DoublePrice botón. Para establecer las propiedades ConnectionString y UpdateCommand, seleccione el control SqlDataSource y, a continuación, vaya a la ventana Propiedades. La propiedad ConnectionString enumera esas cadenas de conexión ya almacenadas en Web.config una lista desplegable; elija la opción NorthwindConnectionString como se muestra en la figura 6.

Configure the SqlDataSource to Use the NorthwindConnectionString

Figura 06: Configurar SqlDataSource para usar la clase NorthwindConnectionString (Haga clic para ver la imagen de tamaño completo)

Para establecer la UpdateCommand propiedad, busque la opción UpdateQuery en la ventana Propiedades. Esta propiedad, cuando está seleccionada, muestra un botón con puntos suspensivos; Haga clic en este botón para mostrar el cuadro de diálogo Comando y Editor de parámetros que se muestra en la figura 7. Escriba la siguiente UPDATE instrucción en el cuadro de texto del cuadro de diálogo:

UPDATE Products SET UnitPrice = UnitPrice * 2

Esta instrucción, cuando se ejecuta, duplicará el valor UnitPrice de cada registro de la tabla Products.

Set SqlDataSource's UpdateCommand Property

Figura 07: Establecer la propiedad de UpdateCommand SqlDataSource (haga clic para ver la imagen de tamaño completo)

Después de establecer estas propiedades, el marcado declarativo de los controles Button y SqlDataSource deben ser similares a los siguientes:

<asp:Button ID="DoublePrice" runat="server" 
 Text="Double Product Prices" />

<asp:SqlDataSource ID="DoublePricesDataSource" runat="server" 
 UpdateCommand="UPDATE Products SET UnitPrice = UnitPrice * 2" 
 ConnectionString="<%$ ConnectionStrings:NorthwindConnectionString %>" 
 ProviderName="<%$ ConnectionStrings:NorthwindConnectionString.ProviderName %>">
</asp:SqlDataSource>

Todo lo que queda es llamar a su Update método cuando se hace clic en el DoublePrice botón. Cree un controlador de eventos Click para el botón DoublePrice y agregue el código siguiente:

protected void DoublePrice_Click(object sender, EventArgs e)
{
    // Double the prices
    DoublePricesDataSource.Update();
}

Para probar esta funcionalidad, visite la página ~/Admin/Products.aspx que creamos en el paso 1 y haga clic en el botón "Precios dobles de productos". Al hacer clic en el botón, se produce un postback y se ejecuta el DoublePrice controlador de eventos del botón Click, duplicando los precios de todos los productos. A continuación, se vuelve a representar la página y se devuelve el marcado y se vuelve a mostrar en el explorador. GridView en la página de contenido, sin embargo, muestra los mismos precios que antes de hacer clic en el botón "Precios de productos dobles". Esto se debe a que los datos cargados inicialmente en GridView tenían su estado almacenado en estado de vista, por lo que no se vuelve a cargar en postbacks a menos que se indique lo contrario. Si visita otra página y vuelve a la página ~/Admin/Products.aspx, verá los precios actualizados.

Paso 3: Generar un evento cuando se duplican los precios

Dado que GridView en la página ~/Admin/Products.aspx no refleja inmediatamente el doble de precios, un usuario puede pensar que no hizo clic en el botón "Precios de productos dobles" o que no funcionó. Pueden intentar hacer clic en el botón varias veces más, duplicando los precios de nuevo y de nuevo. Para corregir esto, es necesario que la cuadrícula de la página de contenido muestre los nuevos precios inmediatamente después de duplicarlos.

Como se explicó anteriormente en este tutorial, es necesario generar un evento en la página maestra cada vez que el usuario hace clic en el botón DoublePrice. Un evento es una manera de que una clase (un publicador de eventos) notifique a otro conjunto de otras clases (los suscriptores de eventos) que ha ocurrido algo interesante. En este ejemplo, la página maestra es el publicador de eventos; esas páginas de contenido que le importan cuando se hace clic en el DoublePrice botón son los suscriptores.

Una clase se suscribe a un evento mediante la creación de un controlador de eventos, que es un método que se ejecuta en respuesta al evento que se está generando. El publicador define los eventos que genera definiendo un delegado de eventos. El delegado de eventos especifica qué parámetros de entrada debe aceptar el controlador de eventos. En .NET Framework, los delegados de eventos no devuelven ningún valor y aceptan dos parámetros de entrada:

  • Un Objectque identifica el origen del evento y
  • una clase derivada de System.EventArgs

El segundo parámetro pasado a un controlador de eventos puede incluir información adicional sobre el evento. Aunque la clase base EventArgs no pasa información, .NET Framework incluye una serie de clases que extienden EventArgs y abarcan propiedades adicionales. Por ejemplo, se pasa una instancia CommandEventArgs a controladores de eventos que responden al evento Command e incluye dos propiedades informativas: CommandArgument y CommandName.

Nota:

Para obtener más información sobre cómo crear, generar y controlar eventos, vea Eventos y delegados y delegados de eventos en inglés simple.

Para definir un evento, use la sintaxis siguiente:

public event eventDelegate eventName;

Dado que solo necesitamos alertar a la página de contenido cuando el usuario ha hecho clic en el botón DoublePrice y no necesita pasar ninguna otra información adicional, podemos usar el delegado EventHandlerde eventos, que define un controlador de eventos que acepta como segundo parámetro un objeto de tipo System.EventArgs. Para crear el evento en la página maestra, agregue la siguiente línea de código a la clase de código subyacente de la página maestra:

public partial class Site : System.Web.UI.MasterPage
{
    public event EventHandler PricesDoubled;

    ...
}

El código anterior agrega un evento público a la página maestra denominada PricesDoubled. Ahora es necesario generar este evento después de que se hayan duplicado los precios. Para generar un evento, use la sintaxis siguiente:

if (eventName != null)
    eventName(sender, eventArgs);

Donde sender y eventArgs son los valores que desea pasar al controlador de eventos del suscriptor.

Actualiza el manejador de eventos DoublePriceClick con el siguiente código:

protected void DoublePrice_Click(object sender, EventArgs e)
{
    // Double the prices
    DoublePricesDataSource.Update();

    // Refresh RecentProducts
    RecentProducts.DataBind();

    // Raise the PricesDoubled event
    if (PricesDoubled != null)
    PricesDoubled(this, EventArgs.Empty);
}

Como antes, el controlador de eventos Click comienza llamando al DoublePricesDataSource método del control SqlDataSourceUpdate para duplicar los precios de todos los productos. A continuación, hay dos adiciones al controlador de eventos. En primer lugar, se actualizan los RecentProducts datos de GridView. Esta clase GridView se agregó a la página maestra del tutorial anterior y muestra los cinco productos agregados más recientemente. Necesitamos actualizar esta cuadrícula para que muestre los precios just-duplicados para estos cinco productos. Después de eso, se genera el evento PricesDoubled. Se envía una referencia a la propia página maestra (this) al controlador de eventos como origen del evento y se envía un objeto vacío EventArgs como argumentos de evento.

Paso 4: Controlar el evento en la página de contenido

En este punto, la página maestra genera su PricesDoubled evento cada vez que se hace clic en el Botón control DoublePrice. Sin embargo, esto es solo la mitad de la batalla- todavía necesitamos controlar el evento en el suscriptor. Esto implica dos pasos: crear el controlador de eventos y agregar código de cableado de eventos para que cuando se genere el evento, se ejecute el controlador de eventos.

Empiece por crear un controlador de eventos denominado Master_PricesDoubled. Debido a cómo definimos el evento PricesDoubled en la página maestra, los dos parámetros de entrada del controlador de eventos deben ser de tipos Object y EventArgs, respectivamente. En el controlador de eventos, llame al método ProductsGrid de GridView DataBind para volver a enlazar los datos a la cuadrícula.

private void Master_PricesDoubled(object sender, EventArgs e)
{
    // Rebind data to ProductsGrid
    ProductsGrid.DataBind();
}

El código del controlador de eventos está completo, pero aún tenemos que conectar el evento de PricesDoubled la página maestra a este controlador de eventos. El suscriptor transfiere un evento a un controlador de eventos a través de la sintaxis siguiente:

publisher.eventName += new eventDelegate(methodName);

publisher es una referencia al objeto que ofrece eventNamey methodName es el nombre del controlador de eventos definido en el suscriptor que tiene una firma correspondiente al eventDelegate. En otras palabras, si el delegado de eventos es EventHandler, luego el methodName debe ser el nombre de un método en el suscriptor que no devuelve un valor y acepta dos parámetros de entrada de tiposObject y EventArgs respectivamente.

Este código de cableado de eventos debe ejecutarse en la primera página visita y posteriores postbacks y debe producirse en un punto del ciclo de vida de la página que precede cuando se puede generar el evento. Un buen momento para agregar código de cableado de eventos está en la fase PreInit, que se produce muy pronto en el ciclo de vida de la página.

Abra ~/Admin/Products.aspx y cree un Page_PreInit controlador de eventos:

protected void Page_PreInit(object sender, EventArgs e)
{
    // TODO: Put event wiring logic here
}

Para completar este código de cableado, necesitamos una referencia mediante programación a la página maestra de la página de contenido. Como se indicó en el tutorial anterior, hay dos maneras de hacerlo:

  • Al convertir la propiedad de Page.Master tipo flexible en el tipo de página maestra adecuado, o bien
  • Añadiendo una directiva @MasterType en la página .aspx y utilizando después la propiedad fuertemente tipada Master.

Vamos a usar este último enfoque. Agregue la siguiente @MasterType directiva a la parte superior del marcado declarativo de la página:

<%@ MasterType VirtualPath="~/Site.master" %>

A continuación, agregue el siguiente código de cableado de eventos en el Page_PreInit controlador de eventos:

protected void Page_PreInit(object sender, EventArgs e)
{
    // Create an event handler for the master page's PricesDoubled event
    Master.PricesDoubled += new EventHandler(Master_PricesDoubled);
}

Con este código en su lugar, GridView en la página de contenido se actualiza cada vez que se hace clic en el DoublePrice botón.

Las cifras 8 y 9 ilustran este comportamiento. En la figura 8 se muestra la página cuando se visita por primera vez. Tenga en cuenta que los valores de precio en RecentProducts GridView (en la columna izquierda de la página maestra) y GridView ProductsGrid (en la página de contenido). La figura 9 muestra la misma pantalla inmediatamente después de hacer clic en el botón DoublePrice. Como puede ver, los nuevos precios se reflejan instantáneamente en ambos GridViews.

The Initial Price Values

Figura 08: Los valores iniciales de precio (haga clic para ver la imagen de tamaño completo)

The Just-Doubled Prices are Displayed in the GridViews

Figura 09: Los precios just-duplicados se muestran en GridViews (haga clic para ver la imagen de tamaño completo)

Resumen

Idealmente, una página maestra y sus páginas de contenido son completamente independientes entre sí y no requieren ningún nivel de interacción. Sin embargo, si tiene una página maestra o página de contenido que muestra los datos que se pueden modificar desde la página maestra o la página de contenido, es posible que tenga que hacer que la página maestra avise a la página de contenido (o viceversa) cuando se modifiquen los datos para que se pueda actualizar la pantalla. En el tutorial anterior vimos cómo hacer que una página de contenido interactúe mediante programación con su página maestra; en este tutorial hemos visto cómo hacer que una página maestra inicie la interacción.

Aunque la interacción mediante programación entre un contenido y una página maestra puede originarse en el contenido o en la página maestra, el patrón de interacción usado depende de la originación. Las diferencias se deben al hecho de que una página de contenido tiene una sola página maestra, pero una página maestra puede tener muchas páginas de contenido diferentes. En lugar de tener una página maestra directamente interactuar con una página de contenido, un mejor enfoque es hacer que la página maestra genere un evento para indicar que se ha realizado alguna acción. Esas páginas de contenido que se preocupan por la acción pueden crear controladores de eventos.

¡Feliz programación!

Lecturas adicionales

Para obtener más información sobre los temas tratados en este tutorial, consulte los siguientes recursos:

Acerca del autor

Scott Mitchell, autor de varios libros de ASP/ASP.NET y fundador de 4GuysFromRolla.com, ha estado trabajando con tecnologías web de Microsoft desde 1998. Scott trabaja como consultor independiente, entrenador y escritor. Su último libro es Sams Teach Yourself ASP.NET 3.5 in 24 Hours. Se puede contactar con Scott en mitchell@4GuysFromRolla.com o a través de su blog en http://ScottOnWriting.NET.

Agradecimientos especiales a

Muchos revisores han evaluado esta serie de tutoriales. El revisor principal de este tutorial fue Suchi Banerjee. ¿Le interesa revisar mis próximos artículos de MSDN? Si es así, escríbame a mitchell@4GuysFromRolla.com