Compartir a través de


Dar formato a los controles DataList y Repeater en función de los datos (VB)

de Scott Mitchell

Descargar PDF

En este tutorial se describen ejemplos de cómo se da formato a la apariencia de los controles DataList y Repeater, ya sea mediante funciones de formato dentro de plantillas o controlando el evento DataBound.

Introducción

Como vimos en el tutorial anterior, DataList ofrece una serie de propiedades relacionadas con el estilo que afectan a su apariencia. En concreto, vimos cómo asignar clases CSS predeterminadas a las propiedades DataList s HeaderStyle, ItemStyle, AlternatingItemStyley SelectedItemStyle . Además de estas cuatro propiedades, DataList incluye una serie de otras propiedades relacionadas con el estilo, como Font, ForeColor, BackColory BorderWidth, por nombrar algunas. El control Repeater no contiene ninguna propiedad relacionada con el estilo. Cualquier configuración de estilo de este tipo debe realizarse directamente dentro del marcado en las plantillas del repetidor.

Sin embargo, a menudo, el formato de los datos depende de los propios datos. Por ejemplo, al enumerar productos, es posible que deseemos mostrar la información del producto en un color de fuente gris claro si se interrumpe, o es posible que deseemos resaltar el UnitsInStock valor si es cero. Como vimos en los tutoriales anteriores, GridView, DetailsView y FormView ofrecen dos formas distintas de dar formato a su apariencia en función de sus datos:

  • El DataBound evento crea un controlador de eventos para el evento adecuado DataBound , que se desencadena después de que los datos se hayan enlazado a cada elemento (para gridView era el RowDataBound evento; para DataList y Repeater es el ItemDataBound evento). En ese controlador de eventos, los datos que acaban de enlazarse se pueden examinar y tomar decisiones de formato. Hemos examinado esta técnica en el tutorial Formato personalizado basado en datos .
  • Funciones de formato en plantillas al usar TemplateFields en los controles DetailsView o GridView, o una plantilla en el control FormView, podemos agregar una función de formato a la clase de código subyacente de la página ASP.NET, la capa lógica de negocios o cualquier otra biblioteca de clases accesible desde la aplicación web. Esta función de formato puede aceptar un número arbitrario de parámetros de entrada, pero debe devolver el CÓDIGO HTML para representarlo en la plantilla. Las funciones de formato se examinaron por primera vez en el tutorial Uso de TemplateFields en el Control GridView.

Ambas técnicas de formato están disponibles con los controles DataList y Repeater. En este tutorial se describen ejemplos que usan ambas técnicas para ambos controles.

Uso delItemDataBoundcontrolador de eventos

Cuando los datos se enlazan a un DataList, ya sea desde un control de origen de datos o asignando los datos mediante programación a la propiedad del control y llamando a su método DataSource, se desencadena el evento DataBind(), se enumera el origen de datos y cada registro de datos se enlaza al DataList. Para cada registro del origen de datos, DataList crea un DataListItem objeto que se enlaza al registro actual. Durante este proceso, DataList genera dos eventos:

  • ItemCreated se desencadena una vez DataListItem ha sido creado
  • ItemDataBound se activa después de que el registro actual se haya enlazado al DataListItem

En los pasos siguientes se describe el proceso de enlace de datos para el control DataList.

  1. Se desencadena el evento DataList.DataBinding

  2. Los datos se enlazan a DataList.

    Para cada registro del origen de datos

    1. Cree un objeto DataListItem
    2. Desencadenar el ItemCreated evento
    3. Vincule el registro a DataListItem
    4. Desencadenar el ItemDataBound evento
    5. Añade DataListItem a la colección Items

Al enlazar datos al control Repeater, avanza a través de la misma secuencia exacta de pasos. La única diferencia es que en lugar de que se creen instancias de DataListItem, el Repeater usa RepeaterItems.

Nota:

Es posible que el lector astuto haya observado una ligera anomalía entre la secuencia de pasos que transcurren cuando DataList y Repeater están enlazados a datos en comparación con cuando GridView está enlazado a datos. Al final del proceso de enlace de datos, GridView genera el DataBound evento; sin embargo, ni el control DataList ni Repeater tienen este evento. Esto se debe a que los controles DataList y Repeater fueron creados durante la época de ASP.NET 1.x, antes de que el patrón de manejo de eventos previo y posterior se volviera común.

Al igual que con GridView, una opción para dar formato en función de los datos es crear un controlador de eventos para el ItemDataBound evento. Este controlador de eventos inspeccionaría los datos que se habían enlazado a DataListItem o RepeaterItem y afectaría al formato del control según sea necesario.

Para el control DataList, los cambios de formato para todo el elemento se pueden implementar mediante las propiedades relacionadas con el DataListItem estilo, que incluyen el estándar Font, ForeColor, BackColor, CssClass, etc. Para afectar al formato de determinados controles web dentro de la plantilla DataList, es necesario acceder mediante programación y modificar el estilo de esos controles web. Hemos visto cómo hacerlo en el tutorial Formato personalizado basado en datos . Al igual que el control Repeater, la RepeaterItem clase no tiene propiedades relacionadas con el estilo; por lo tanto, todos los cambios relacionados con el estilo realizados en un RepeaterItem en el ItemDataBound controlador de eventos deben realizarse mediante programación para acceder a los controles web y actualizarlos dentro de la plantilla.

Dado que la ItemDataBound técnica de formato de DataList y Repeater son prácticamente idénticas, nuestro ejemplo se centrará en el uso de DataList.

Paso 1: mostrar información del producto en la lista de datos

Antes de preocuparnos por el formato, vamos a crear primero una página que use dataList para mostrar la información del producto. En el tutorial anterior creamos una lista de datos cuyo ItemTemplate nombre, categoría, proveedor, cantidad por unidad y precio mostraron cada producto. Vamos a repetir esta funcionalidad aquí en este tutorial. Para ello, puede volver a crear dataList y su ObjectDataSource desde cero, o bien copiar esos controles desde la página creada en el tutorial anterior () y pegarlos en la página de este tutorial (Basics.aspxFormatting.aspx).

Una vez que haya replicado la funcionalidad de DataList y ObjectDataSource desde Basics.aspx en Formatting.aspx, dedique un momento a cambiar la propiedad del DataList en ID de DataList1 a una propiedad más descriptiva en ItemDataBoundFormattingExample. A continuación, vea DataList en un explorador. Como se muestra en la figura 1, la única diferencia de formato entre cada producto es que el color de fondo alterna.

Los productos se enumeran en el control DataList

Figura 1: Los productos aparecen en el control DataList (haga clic para ver la imagen de tamaño completo)

Para este tutorial, vamos a dar formato a DataList de modo que cualquier producto con un precio inferior a 20,00 USD tendrá su nombre y precio unitario resaltado amarillo.

Paso 2: Determinar mediante programación el valor de los datos en el controlador de eventos ItemDataBound

Puesto que solo esos productos con un precio inferior a 20,00 USD tendrán aplicado el formato personalizado, debemos poder determinar cada precio de cada producto. Al enlazar datos a dataList, DataList enumera los registros de su origen de datos y, para cada registro, crea una DataListItem instancia, enlaza el registro del origen de datos a DataListItem. Después de que los datos del registro particular se hayan enlazado al objeto actual DataListItem, se desencadena el evento del DataList ItemDataBound. Podemos crear un controlador de eventos para este evento para inspeccionar los valores de datos del actual DataListItem y, en función de esos valores, realizar los cambios de formato necesarios.

Cree un ItemDataBound evento para DataList y agregue el código siguiente:

Protected Sub ItemDataBoundFormattingExample_ItemDataBound _
    (sender As Object, e As DataListItemEventArgs) _
    Handles ItemDataBoundFormattingExample.ItemDataBound
    If e.Item.ItemType = ListItemType.Item OrElse _
       e.Item.ItemType = ListItemType.AlternatingItem Then
        ' Programmatically reference the ProductsRow instance
        ' bound to this DataListItem
        Dim product As Northwind.ProductsRow = _
            CType(CType(e.Item.DataItem, System.Data.DataRowView).Row, _
                Northwind.ProductsRow)
        ' See if the UnitPrice is not NULL and less than $20.00
        If Not product.IsUnitPriceNull() AndAlso product.UnitPrice < 20 Then
            ' TODO: Highlight the product's name and price
        End If
    End If
End Sub

Aunque el concepto y la semántica detrás del controlador de eventos dataList ItemDataBound son los mismos que los usados por el controlador de eventos de RowDataBound GridView en el tutorial Formato personalizado basado en datos , la sintaxis difiere ligeramente. Cuando se desencadena el ItemDataBound evento, el DataListItem enlazado a los datos se pasa al controlador de eventos correspondiente a través de e.Item (en lugar de e.Row, como con el controlador de eventos del GridView RowDataBound). El controlador de eventos dataList se ItemDataBound activa para cada fila agregada a DataList, incluidas las filas de encabezado, las filas de pie de página y las filas separadoras. Sin embargo, la información del producto solo está enlazada a las filas de datos. Por lo tanto, al usar el ItemDataBound evento para inspeccionar los datos enlazados a DataList, primero debemos asegurarnos de que estamos trabajando con un elemento de datos. Esto se puede lograr comprobando la DataListItem propiedad sItemType, que puede tener uno de los ocho valores siguientes:

  • AlternatingItem
  • EditItem
  • Footer
  • Header
  • Item
  • Pager
  • SelectedItem
  • Separator

Ambos, Item y AlternatingItem``DataListItem, constituyen los elementos de datos de DataList. Suponiendo que estamos trabajando con un Item o un AlternatingItem, accedemos a la instancia real ProductsRow enlazada al DataListItem actual. La DataListItem propiedad s DataItem contiene una referencia al DataRowView objeto , cuya Row propiedad proporciona una referencia al objeto realProductsRow.

A continuación, comprobamos la propiedad ProductsRow de la instancia UnitPrice. Dado que el campo UnitPrice de la tabla Products admite valores NULL, antes de intentar acceder a la propiedad UnitPrice, primero debemos comprobar si tiene un valor NULL usando el método IsUnitPriceNull(). Si el valor UnitPrice no es NULL, comprobamos si es menos de 20,00 USD. Si realmente es inferior a 20,00 USD, entonces es necesario aplicar el formato personalizado.

Paso 3: Resaltar el nombre y el precio del producto

Una vez que sabemos que el precio de un producto es inferior a $20.00, todo lo que queda es resaltar su nombre y precio. Para ello, primero debemos referenciar programáticamente los controles Label en los cuales ItemTemplate se muestran el nombre y el precio del producto. A continuación, necesitamos que muestren un fondo amarillo. Esta información de formato se puede aplicar modificando directamente las propiedades Etiquetas BackColor (LabelID.BackColor = Color.Yellow); lo ideal es que todos los asuntos relacionados con la presentación se expresen a través de hojas de estilos en cascada. De hecho, ya tenemos una hoja de estilos que proporciona el formato deseado definido en Styles.css - AffordablePriceEmphasis, que se creó y se explicó en el tutorial Formato personalizado basado en datos .

Para aplicar el formato, basta con establecer las propiedades de los dos controles Web de etiqueta CssClass en AffordablePriceEmphasis, como se muestra en el código siguiente.

' Highlight the product name and unit price Labels
' First, get a reference to the two Label Web controls
Dim ProductNameLabel As Label = CType(e.Item.FindControl("ProductNameLabel"), Label)
Dim UnitPriceLabel As Label = CType(e.Item.FindControl("UnitPriceLabel"), Label)
' Next, set their CssClass properties
If ProductNameLabel IsNot Nothing Then
    ProductNameLabel.CssClass = "AffordablePriceEmphasis"
End If
If UnitPriceLabel IsNot Nothing Then
    UnitPriceLabel.CssClass = "AffordablePriceEmphasis"
End If

Una vez completado el ItemDataBound controlador de eventos, vuelva a visitar la Formatting.aspx página en un explorador. Como se muestra en la figura 2, esos productos con un precio inferior a 20,00 USD tienen resaltado su nombre y precio.

Esos productos menos de $20,00 están resaltados

Figura 2: Esos productos inferiores a 20,00 USD están resaltados (haga clic para ver la imagen de tamaño completo)

Nota:

Dado que DataList se representa como HTML <table>, sus DataListItem instancias tienen propiedades relacionadas con el estilo que se pueden establecer para aplicar un estilo específico a todo el elemento. Por ejemplo, si queríamos resaltar todo el elemento amarillo cuando su precio era inferior a 20,00 USD, podríamos haber reemplazado el código que hacía referencia a las etiquetas y establecer sus CssClass propiedades con la siguiente línea de código: e.Item.CssClass = "AffordablePriceEmphasis" (vea la figura 3).

Sin embargo, los elementos que componen el control Repeater no ofrecen estas propiedades de nivel de estilo. Por lo tanto, aplicar formato personalizado al repetidor requiere la aplicación de propiedades de estilo a los controles web dentro de las plantillas del repetidor, al igual que hicimos en la figura 2.

El producto completo está resaltado para productos por debajo de 20,00 USD

Figura 3: Todo el elemento de producto está resaltado para productos menores de 20,00 USD (haga clic para ver la imagen de tamaño completo)

Uso de funciones de formato desde dentro de la plantilla

En el tutorial Uso de TemplateFields en el control GridView vimos cómo usar una función de formato dentro de un TemplateField de GridView para aplicar formato personalizado basado en los datos enlazados a las filas de GridView. Una función de formato es un método que se puede invocar desde una plantilla y devuelve el CÓDIGO HTML que se va a emitir en su lugar. Las funciones de formato pueden residir en la clase de código subyacente de la página ASP.NET o pueden centralizarse en archivos de clase de la App_Code carpeta o en un proyecto de biblioteca de clases independiente. Mover la función de formato fuera de la clase de código subyacente de la página de ASP.NET es ideal si planea usar la misma función de formato en varias páginas de ASP.NET o en otras aplicaciones web de ASP.NET.

Para mostrar las funciones de formato, vamos a hacer que la información del producto incluya el texto [DESCATALOGADO] junto al nombre del producto si está descatalogado. Además, vamos a tener el precio resaltado amarillo si es menor que $20.00 (como hicimos en el ItemDataBound ejemplo del controlador de eventos); si el precio es $20.00 o superior, dejemos que no muestre el precio real, sino el texto, Llame a para una cotización de precios. En la figura 4 se muestra una captura de pantalla de la lista de productos con estas reglas de formato aplicadas.

Captura de pantalla que muestra los productos enumerados en el control DataList, con el precio de los productos que cuestan más de 20,00 USD reemplazados por el texto

Figura 4: Para productos costosos, el precio se reemplaza por el texto, llame a para una cotización de precio (haga clic para ver la imagen de tamaño completo)

Paso 1: Crear las funciones de formato

En este ejemplo necesitamos dos funciones de formato: una que muestre el nombre del producto junto con el texto [DESCATALOGADO], si es necesario; y otra que muestre un precio resaltado si es inferior a 20,00 USD, o el texto "Llame para obtener una cotización de precio," de lo contrario. Vamos a crear estas funciones en la clase de código subyacente de la página ASP.NET y nombrarlas DisplayProductNameAndDiscontinuedStatus y DisplayPrice. Ambos métodos deben devolver el CÓDIGO HTML para representarse como una cadena y ambos deben marcarse Protected (o Public) para poder invocarse desde la parte de sintaxis declarativa de la página ASP.NET. El código de estos dos métodos sigue:

Protected Function DisplayProductNameAndDiscontinuedStatus _
    (productName As String, discontinued As Boolean) As String
    ' Return just the productName if discontinued is false
    If Not discontinued Then
        Return productName
    Else
        ' otherwise, return the productName appended with the text "[DISCONTINUED]"
        Return String.Concat(productName, " [DISCONTINUED]")
    End If
End Function
Protected Function DisplayPrice(product As Northwind.ProductsRow) As String
    ' If price is less than $20.00, return the price, highlighted
    If Not product.IsUnitPriceNull() AndAlso product.UnitPrice < 20 Then
        Return String.Concat("<span class="AffordablePriceEmphasis">", _
                             product.UnitPrice.ToString("C"), "</span>")
    Else
        ' Otherwise return the text, "Please call for a price quote"
        Return "<span>Please call for a price quote</span>"
    End If
End Function

Tenga en cuenta que el DisplayProductNameAndDiscontinuedStatus método acepta los valores de los productName campos de datos y discontinued como valores escalares, mientras que el DisplayPrice método acepta una ProductsRow instancia (en lugar de un unitPrice valor escalar). Cualquier enfoque funcionará; sin embargo, si la función de formato está trabajando con valores escalares que pueden contener valores de base de datos NULL (como UnitPrice), y ni ProductName ni Discontinued permiten valores NULL, se debe tener especial cuidado en el manejo de estas entradas escalares.

En concreto, el parámetro de entrada debe ser de tipo Object , ya que el valor entrante podría ser una DBNull instancia en lugar del tipo de datos esperado. Además, se debe realizar una comprobación para determinar si el valor entrante es o no un valor de base de datos NULL . Es decir, si queremos que el DisplayPrice método acepte el precio como un valor escalar, tendríamos que usar el código siguiente:

Protected Function DisplayPrice(ByVal unitPrice As Object) As String
    ' If price is less than $20.00, return the price, highlighted
    If Not Convert.IsDBNull(unitPrice) AndAlso CType(unitPrice, Decimal) < 20 Then
        Return String.Concat("<span class="AffordablePriceEmphasis">", _
            CType(unitPrice, Decimal).ToString("C"), "</span>")
    Else
        ' Otherwise return the text, "Please call for a price quote"
        Return "<span>Please call for a price quote</span>"
    End If
End Function

Tenga en cuenta que el unitPrice parámetro de entrada es de tipo Object y que la instrucción condicional se ha modificado para determinar si unitPrice es DBNull o no. Además, dado que el parámetro de entrada unitPrice se pasa como un Object, debe convertirse a un valor decimal.

Paso 2: Llamar a la función de formato desde la clase ItemTemplate de DataList

Con las funciones de formato agregadas a la clase de código subyacente de la página ASP.NET, todo lo que queda es invocar estas funciones de formato desde dataList s ItemTemplate. Para llamar a una función de formato desde una plantilla, coloque la llamada de función dentro de la sintaxis de enlace de datos.

<%# MethodName(inputParameter1, inputParameter2, ...) %>

En el DataList ItemTemplate el control Web ProductNameLabel Label muestra actualmente el nombre del producto asignando a su propiedad Text el resultado de <%# Eval("ProductName") %>. Para que muestre el nombre más el texto [DISCONTINUED], si es necesario, actualice la sintaxis declarativa para que, en su lugar, asigne a la Text propiedad el valor del DisplayProductNameAndDiscontinuedStatus método. Al hacerlo, debemos pasar el nombre del producto y los valores descontinuados mediante la Eval("columnName") sintaxis . Eval devuelve un valor de tipo Object, pero el DisplayProductNameAndDiscontinuedStatus método espera parámetros de entrada de tipo String y Boolean; por lo tanto, debemos convertir los valores devueltos por el Eval método a los tipos de parámetros de entrada esperados, de la siguiente manera:

<h4>
    <asp:Label ID="ProductNameLabel" runat="server"
        Text='<%# DisplayProductNameAndDiscontinuedStatus((string) Eval("ProductName"),
              (bool) Eval("Discontinued")) %>'>
    </asp:Label>
</h4>

Para mostrar el precio, simplemente podemos establecer la UnitPriceLabel propiedad Label s Text en el valor devuelto por el DisplayPrice método , al igual que hicimos para mostrar el nombre del producto y el texto [DISCONTINUED]. Sin embargo, en lugar de pasar el UnitPrice como un parámetro de entrada escalar, pasamos toda la instancia ProductsRow.

<asp:Label ID="UnitPriceLabel" runat="server"
    Text='<%# DisplayPrice((Northwind.ProductsRow)
          ((System.Data.DataRowView) Container.DataItem).Row) %>'>
</asp:Label>

Con las llamadas a las funciones de formato implementadas, tómese un momento para ver nuestro progreso en un navegador. La pantalla debe ser similar a la figura 5, con los productos descontinuados incluyendo el texto [DISCONTINUED] y aquellos productos que cuestan más de $20.00 teniendo su precio reemplazado por el texto Llame para solicitar una cotización.

Captura de pantalla que muestra los productos enumerados en el control DataList, con el precio de los productos que cuestan más de 20,00 USD reemplazados por el texto

Figura 5: Para productos costosos, el precio se reemplaza por el texto, llame a para una cotización de precio (haga clic para ver la imagen de tamaño completo)

Resumen

Formatear el contenido de un control DataList o Repeater en función de los datos se puede realizar mediante dos técnicas. La primera técnica consiste en crear un controlador de eventos para el ItemDataBound evento, que se desencadena a medida que cada registro del origen de datos está enlazado a un nuevo DataListItem o RepeaterItem. En el ItemDataBound controlador de eventos, los datos del elemento actual se pueden examinar y, a continuación, se puede aplicar formato al contenido de la plantilla o, para DataListItem s, a todo el elemento.

Como alternativa, el formato personalizado se puede realizar a través de funciones de formato. Una función de formato es un método que se puede invocar desde las plantillas DataList o Repeater s que devuelve el CÓDIGO HTML que se va a emitir en su lugar. A menudo, el CÓDIGO HTML devuelto por una función de formato viene determinado por los valores que se enlazan al elemento actual. Estos valores se pueden pasar a la función de formato, ya sea como valores escalares o pasando todo el objeto enlazado al elemento (como la ProductsRow instancia).

¡Feliz programación!

Acerca del autor

Scott Mitchell, autor de siete 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 2.0 en 24 horas. Se puede contactar con él en mitchell@4GuysFromRolla.com.

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 Yaakov Ellis, Randy Schmidt y Liz Shulok. ¿Le interesaría revisar mis próximos artículos de MSDN? Si es así, mándame un mensaje a mitchell@4GuysFromRolla.com.