Varios ContentPlaceHolders y contenido predeterminado (VB)

por Scott Mitchell

Descargar PDF

Aprenda cómo agregar varios marcadores de contenido a una página maestra y a cómo especificar contenido predeterminado en los marcadores de contenido.

Introducción

En el tutorial anterior hemos visto cómo las páginas maestras permiten a los desarrolladores de ASP.NET crear un diseño coherente para todo el sitio. Las páginas maestras definen el marcado común de todas sus páginas de contenido y las regiones que se pueden personalizar página por página. En el tutorial anterior creamos una página maestra simple (Site.master) y dos páginas de contenido (Default.aspx y About.aspx). Nuestra página maestra consta de dos ContentPlaceHolders denominados head y MainContent, que se encontraban en el elemento <head> y el formulario web, respectivamente. Aunque las páginas de contenido tenían dos controles de contenido, solo se especificó el marcado para el correspondiente a MainContent.

Como se demuestra en los dos controles ContentPlaceHolder de Site.master, una página maestra puede contener varios ContentPlaceHolders. Además, la página maestra puede especificar el marcado predeterminado para los controles ContentPlaceHolder. Una página de contenido, por lo tanto, puede especificar opcionalmente su propio marcado o usar el marcado predeterminado. En este tutorial veremos el uso de varios controles de contenido en la página maestra y aprenderemos cómo definir el marcado predeterminado en los controles ContentPlaceHolder.

Paso 1: Agregar controles ContentPlaceHolder adicionales a la página maestra

Muchos diseños de sitios web contienen varias áreas en la pantalla que se personalizan página a página. Site.master, la página maestra que creamos en el tutorial anterior, contiene un único ContentPlaceHolder dentro del formulario web denominado MainContent. En concreto, este ContentPlaceHolder se encuentra dentro del elemento mainContent<div>.

En la figura 1 se muestra Default.aspx visto a través de un explorador. La región redondeada en rojo es el marcado específico de la página correspondiente a MainContent.

The Circled Region Shows the Area Currently Customizable on a Page-by-Page Basis

Figura 01: La región redondeada muestra el área personalizable actualmente página por página (haga clic para ver la imagen en tamaño completo)

Imagine que además de la región que se muestra en la figura 1 también es necesario agregar elementos específicos de página a la columna de la izquierda debajo de las secciones Lecciones y Noticias. Para ello, agregamos otro control ContentPlaceHolder a la página maestra. Para continuar, abra la página maestra Site.master en Visual Web Developer y arrastre un control ContentPlaceHolder desde el cuadro de herramientas al diseñador después de la sección Noticias. Establezca ContentPlaceHolder ID en LeftColumnContent.

Add a ContentPlaceHolder Control to the Master Page's Left Column

Figura 02: Agregar un control ContentPlaceHolder en la columna de la izquierda de la página maestra (haga clic para ver la imagen en tamaño completo )

Al añadir ContentPlaceHolder LeftColumnContent a la página maestra, podemos definir contenido para esta región página por página incluyendo un control de contenido en la página cuyo valor ContentPlaceHolderID está establecido en LeftColumnContent. Este proceso se examina en el paso 2.

Paso 2: Definir contenido para el nuevo ContentPlaceHolder en las páginas de contenido

Al agregar una nueva página de contenido en el sitio web, Visual Web Developer crea automáticamente un control de contenido en la página para cada ContentPlaceHolder en la página maestra seleccionada. Después de agregar un ContentPlaceHolder LeftColumnContent a nuestra página maestra en el paso 1, las nuevas páginas ASP.NET tendrán tres controles de contenido.

Para ilustrar esto, agregue una nueva página de contenido al directorio raíz denominado MultipleContentPlaceHolders.aspx enlazado a la página maestra Site.master. Visual Web Developer crea esta página con el siguiente marcado declarativo:

<%@ Page Language="VB" MasterPageFile="~/Site.master" AutoEventWireup="false" CodeFile="MultipleContentPlaceHolders.aspx.vb" Inherits="MultipleContentPlaceHolders" Title="Untitled Page" %>
<asp:Content ID="Content1" ContentPlaceHolderID="head" Runat="Server">
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" Runat="Server">
</asp:Content>
<asp:Content ID="Content3" ContentPlaceHolderID="LeftColumnContent" Runat="Server">
</asp:Content>

Escriba contenido en el control de contenido que hace referencia a MainContent ContentPlaceHolders (Content2). A continuación, agregue el marcado siguiente al control de contenido Content3 (que hace referencia a ContentPlaceHolder LeftColumnContent):

<h3>Page-Specific Content</h3>
<ul>
 <li>This content is defined in the content page.</li>
 <li>The master page has two regions in the Web Form that are editable on a
 page-by-page basis.</li>
</ul>

Después de agregar este marcado, visite la página desde un explorador. Como se muestra en la figura 3, el marcado colocado en el control de contenido Content3 se muestra en la columna de la izquierda debajo de la sección Noticias (redondeada en rojo). El marcado colocado en Content2 se muestra en la parte derecha de la página (redondeado en azul).

The Left Column Now Includes Page-Specific Content Beneath the News Section

Figura 03: La columna de la izquierda ahora incluye contenido específico de la página debajo de la sección Noticias (haga clic para ver la imagen en tamaño completo)

Definir contenido en páginas de contenido existentes

La creación de una nueva página de contenido incorpora automáticamente el control ContentPlaceHolder que hemos agregado en el paso 1. Sin embargo, nuestras dos páginas de contenido existentes, About.aspx y Default.aspx, no tienen un control de contenido para ContentPlaceHolder LeftColumnContent. Para especificar contenido para este ContentPlaceHolder en estas dos páginas existentes, es necesario agregar un control de contenido nosotros mismos.

A diferencia de la mayoría de los controles web ASP.NET, el cuadro de herramientas para Visual Web Developer no incluye un elemento de control de contenido. Podemos escribir manualmente en el marcado declarativo del control de contenido en la vista Origen, pero es más fácil y rápido utilizar la vista Diseño. Abra la página About.aspx y cambie a la vista Diseño. Tal como se muestra en la figura 4, el ContentPlaceHolder LeftColumnContent aparece en la vista Diseño; si hace clic sobre él, el título mostrado dice: "LeftColumnContent (Master)." La incorporación de "Master" en el título indica que no hay ningún control de contenido definido en la página para este ContentPlaceHolder. Si existe un control de contenido para el ContentPlaceHolder, como en el caso de MainContent, el título dirá: "ContentPlaceHolderID (Custom)."

Para agregar un control de contenido para ContentPlaceHolder LeftColumnContent a About.aspx, expanda la etiqueta inteligente de ContentPlaceHolder y haga clic en el vínculo Crear contenido personalizado.

The Design View for About.aspx Shows the LeftColumnContent ContentPlaceHolder

Figura 04: La vista Diseño para About.aspx muestra el ContentPlaceHolder LeftColumnContent (haga clic para ver la imagen en tamaño completo )

Al hacer clic en el vínculo Crear contenido personalizado, se genera el control de contenido necesario en la página y se establece su propiedad ContentPlaceHolderID en ContentPlaceHolder ID. Por ejemplo, al hacer clic en el vínculo Crear contenido personalizado para la región LeftColumnContent en About.aspx, se añade el marcado declarativo siguiente a la página:

<asp:Content ID="Content3" runat="server" 
 contentplaceholderid="LeftColumnContent">
 
</asp:Content>

Omitir controles de contenido

ASP.NET no requiere que todas las páginas de contenido incluyan controles de contenido para cada elemento ContentPlaceHolder definido en la página maestra. Si se omite un control de contenido, el motor ASP.NET utiliza el marcado definido en el ContentPlaceHolder en la página maestra. Este marcado se conoce como contenido predeterminado de ContentPlaceHolder y es útil en escenarios en los que el contenido de alguna región es común entre la mayoría de las páginas pero debe personalizarse para un pequeño número de páginas. En el paso 3 se examina la especificación del contenido predeterminado en la página maestra.

Actualmente, Default.aspx contiene dos controles de contenido para los ContentPlaceHolders head y MainContent; no contiene un control de contenido para LeftColumnContent. Por lo tanto, cuando Default.aspx se representa en LeftColumnContent, se utiliza el contenido predeterminado de ContentPlaceHolder. Dado que todavía tenemos que definir cualquier contenido predeterminado para este ContentPlaceHolder, el efecto neto es que no se emite ningún marcado para esta región. Para comprobar este comportamiento, visite Default.aspx en un explorador. Como se muestra en la figura 5, no se emite ningún marcado en la columna de la izquierda debajo de la sección Noticias.

No Content is Rendered for the LeftColumnContent ContentPlaceHolder

Figura 05: No se representa ningún contenido para el ContentPlaceHolder LeftColumnContent (haga clic para ver la imagen en tamaño completo)

Paso 3: Especificar contenido predeterminado en la página maestra

Algunos diseños de sitios web incluyen una región cuyo contenido es el mismo para todas las páginas del sitio, excepto para una o dos excepciones. Piense en un sitio web que admita cuentas de usuario. Este sitio requiere una página de inicio de sesión en la que los visitantes puedan escribir sus credenciales para iniciar sesión en él. Para acelerar el proceso de inicio de sesión, los diseñadores de sitios web pueden incluir cuadros de texto de nombre de usuario y contraseña en la esquina superior izquierda de cada página para permitir que los usuarios inicien sesión sin tener que visitar explícitamente la página de inicio de sesión. Aunque estos cuadros de texto de nombre de usuario y contraseña son útiles en la mayoría de las páginas, son redundantes en la página de inicio de sesión, que ya contiene cuadros de texto para las credenciales del usuario.

Para implementar este diseño, puede crear un control ContentPlaceHolder en la esquina superior izquierda de la página maestra. Cada página que necesita que muestre los cuadros de texto de nombre de usuario y contraseña en la esquina superior izquierda crearía un control de contenido para este ContentPlaceHolder y agregaría la interfaz necesaria. Por otro lado, la página de inicio de sesión no añadiría un control de contenido para este ContentPlaceHolder o crearía un control de contenido sin marcado definido. La desventaja de este método es que tenemos que recordar agregar los cuadros de texto de nombre de usuario y contraseña a cada página que agreguemos al sitio (excepto en la página de inicio de sesión). Esto puede ser problemático. Es probable que nos olvidemos de agregar estos cuadros de texto a una página o dos o, lo que es peor, es posible que no implementemos la interfaz correctamente (quizás agregando solo un cuadro de texto en lugar de dos).

La mejor solución es definir los cuadros de texto de nombre de usuario y contraseña como contenido predeterminado del ContentPlaceHolder. Al hacerlo, solo es necesario invalidar este contenido predeterminado en esas pocas páginas que no muestran los cuadros de texto de nombre de usuario y contraseña (la página de inicio de sesión, por ejemplo). Para ilustrar la especificación del contenido predeterminado para un control ContentPlaceHolder vamos a implementar el escenario que se acaba de analizar.

Nota:

El resto de este tutorial trata sobre actualizar nuestro sitio web para incluir una interfaz de inicio de sesión en la columna de la izquierda en todas las páginas excepto en la página de inicio de sesión. Sin embargo, este tutorial no muestra cómo configurar el sitio web para admitir cuentas de usuario. Para obtener más información sobre este tema, consulte mis tutoriales de autenticación de formularios, autorización, cuentas de usuario y roles.

Agregar un ContentPlaceHolder y especificar su contenido predeterminado

Abra la página maestra Site.master y agregue el marcado siguiente a la columna de la izquierda entre la sección Etiqueta y Lecciones DateDisplay:

<asp:ContentPlaceHolder ID="QuickLoginUI" runat="server">
 <asp:Login ID="QuickLogin" runat="server" 
    TitleText="<h3>Sign In</h3>"
    FailureAction="RedirectToLoginPage">
 </asp:Login>
</asp:ContentPlaceHolder>

Después de agregar este marcado, la vista Diseño de la página maestra debe ser similar a la figura 6.

The Master Page Includes a Login Control

Figura 06: La página maestra incluye un control de inicio de sesión (haga clic para ver la imagen en tamaño completo)

Este ContentPlaceHolder, QuickLoginUI, tiene un control web de inicio de sesión así como su contenido predeterminado. El control de inicio de sesión muestra una interfaz de usuario que solicita al usuario su nombre de usuario y contraseña junto con un botón de iniciar sesión. Al hacer clic en el botón de iniciar sesión, el control de inicio de sesión valida internamente las credenciales del usuario en la API de pertenencia. Para usar este control de inicio de sesión en la práctica, debe configurar el sitio para que use Pertenencia. Este tema está fuera del ámbito de este tutorial; Consulte mis tutoriales de autenticación de formularios, autorización, cuentas de usuario y roles para obtener más información sobre cómo compilar una aplicación web que admita cuentas de usuario.

No dude en personalizar el comportamiento o la apariencia del control de inicio de sesión. He establecido dos de sus propiedades: TitleText y FailureAction. El valor de propiedad TitleText, que tiene como valor predeterminado "Iniciar sesión", se muestra en la parte superior del control de la interfaz de usuario. He establecido esta propiedad para que muestre el texto "Iniciar sesión" como un elemento <h3>. La propiedad FailureAction indica qué hacer si las credenciales del usuario no son válidas. El valor predeterminado es Refresh, que deja al usuario en la misma página y muestra un mensaje de error dentro del control de inicio de sesión. Lo he cambiado a RedirectToLoginPage, que envía al usuario a la página de inicio de sesión en caso de que las credenciales no sean válidas. Prefiero enviar al usuario a la página de inicio de sesión cuando un usuario intenta iniciar sesión desde alguna otra página, pero se produce un error, ya que la página de inicio de sesión puede contener instrucciones y opciones adicionales que no caben fácilmente en la columna de la izquierda. Por ejemplo, la página de inicio de sesión podría incluir opciones para recuperar una contraseña olvidada o para crear una nueva cuenta.

Crear la página de inicio de sesión e invalidar el contenido predeterminado

Una vez completada la página maestra, nuestro siguiente paso es crear la página de inicio de sesión. Agregue una página ASP.NET al directorio raíz del sitio denominado Login.aspx, enlazándola a la página maestra Site.master. Al hacerlo se creará una página con cuatro controles de contenido, uno para cada uno de los ContentPlaceHolders definidos en Site.master.

Agregue un control de inicio de sesión al control de contenido MainContent. Del mismo modo, no dude en agregar contenido a la región LeftColumnContent. Sin embargo, asegúrese de dejar vacío el control de contenido para el ContentPlaceHolder QuickLoginUI. Esto garantizará que el control de inicio de sesión no aparezca en la columna de la izquierda de la página de inicio de sesión.

Después de definir el contenido de las regiones MainContent y LeftColumnContent, el marcado declarativo de la página de inicio de sesión debe ser similar al siguiente:

<%@ Page Language="VB" MasterPageFile="~/Site.master" AutoEventWireup="false" CodeFile="Login.aspx.vb" Inherits="Login" Title="Untitled Page" %>
<asp:Content ID="Content1" ContentPlaceHolderID="head" Runat="Server">
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" Runat="Server">
 <h2>
 Sign In</h2>
 <p>
 <asp:Login ID="Login1" runat="server" TitleText="">
 </asp:Login>
 </p>
</asp:Content>
<asp:Content ID="Content3" ContentPlaceHolderID="QuickLoginUI" Runat="Server">
</asp:Content>
<asp:Content ID="Content4" ContentPlaceHolderID="LeftColumnContent" Runat="Server">
 <h3>Sign In Tasks</h3>
 <ul>
 <li>Create a New Account</li>
 <li>Recover Forgotten Password</li>
 </ul>
 <p>TODO: Turn the above text into links...</p>
</asp:Content>

En la figura 7 se muestra esta página vista desde un explorador. Dado que esta página especifica un control de contenido para ContentPlaceHolder QuickLoginUI, invalida el contenido predeterminado especificado en la página maestra. El efecto neto es que el control de inicio de sesión mostrado en la vista Diseño de la página maestra (vea la figura 6) no se representa en esta página.

The Login Page Represses the QuickLoginUI ContentPlaceHolder's Default Content

Figura 07: La página de inicio de sesión reprime el contenido predeterminado de ContentPlaceHolder QuickLoginUI ( haga clic para ver la imagen en tamaño completo)

Utilizar el contenido predeterminado en páginas nuevas

Queremos mostrar el control de inicio de sesión en la columna de la izquierda en todas las páginas excepto en la página de inicio de sesión. Para lograrlo, todas las páginas de contenido excepto la página de inicio de sesión deben omitir un control de contenido para ContentPlaceHolder QuickLoginUI. Al omitir un control de contenido, se usará en su lugar el contenido predeterminado de ContentPlaceHolder.

Nuestras páginas de contenido existentes, Default.aspx, About.aspx y MultipleContentPlaceHolders.aspx, no incluyen un control de contenido para QuickLoginUI porque se crearon antes de agregar ese control ContentPlaceHolder a la página maestra. Por lo tanto, no es necesario actualizar las páginas existentes. Sin embargo, las páginas nuevas añadidas al sitio web incluyen un control de contenido para ContentPlaceHolder QuickLoginUI de forma predeterminada. Esto quiere decir que tenemos que recordar quitar estos controles de contenido cada vez que agregamos una nueva página de contenido (a menos que deseemos invalidar el contenido predeterminado de ContentPlaceHolder, como en el caso de la página de inicio de sesión).

Para quitar el control de contenido, puede eliminar manualmente su marcado declarativo de la vista Origen o, desde la vista Diseño, elegir el vínculo Contenido predeterminado a maestro de su etiqueta inteligente. Cualquiera de los dos métodos quita el control de contenido de la página y genera el mismo efecto neto.

En la figura 8 se muestra Default.aspx visto desde un explorador. Recuerde que Default.aspx solo tiene dos controles de contenido especificados en su marcado declarativo: uno para head y otro para MainContent. Como resultado, se muestra el contenido predeterminado de ContentPlaceHolders LeftColumnContent y QuickLoginUI.

The Default Content for the LeftColumnContent and QuickLoginUI ContentPlaceHolders are Displayed

Figura 08: Se muestra el contenido predeterminado para los ContentPlaceHolders LeftColumnContent y QuickLoginUI (haga clic para ver la imagen en tamaño completo)

Resumen

El modelo de página maestra ASP.NET permite un número arbitrario de ContentPlaceHolders en la página maestra. Además, ContentPlaceHolders incluye contenido predeterminado que se emite en caso de que no haya ningún control de contenido correspondiente en la página de contenido. En este tutorial hemos visto cómo incluir controles ContentPlaceHolder adicionales en la página maestra y cómo definir controles de contenido para estos nuevos ContentPlaceHolders en páginas ASP.NET nuevas y existentes. También hemos visto la especificación de contenido predeterminado en un ContentPlaceHolder, que es útil en escenarios en los que solo una minoría de páginas necesita personalizar el contenido estándar de otro modo dentro de una determinada región.

En el siguiente tutorial examinaremos ContentPlaceHolder head con más detalle. Veremos cómo definir mediante declaración y mediante programación el título, las etiquetas meta y otros encabezados HTML página a página.

¡Feliz programación!

Acerca del autor

Scott Mitchell, autor de varios libros sobre ASP/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 3.5 in 24 Hours. Puede contactar con Scott escribiendo a mitchell@4GuysFromRolla.com o en su blog en http://ScottOnWriting.NET.

Agradecimientos especiales a

Esta serie de tutoriales fue revisada por muchos revisores de gran ayuda. 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.