Optimizar el rendimiento: Texto

WPF incluye compatibilidad para la presentación de contenido de texto mediante el uso de controles de interfaz de usuario (UI) completos. En general, puede dividir la representación de texto en tres capas:

  1. Uso de los objetos Glyphs y GlyphRun directamente.

  2. Uso del objeto FormattedText.

  3. Uso de los controles de alto nivel, como los objetos TextBlock y FlowDocument.

En este tema se proporcionan recomendaciones de rendimiento para la representación de texto.

Representación de texto en el nivel de glifos

Windows Presentation Foundation (WPF) proporciona compatibilidad con texto avanzado, incluido el marcado de nivel de glifos con acceso directo a Glyphs para clientes que quieran interceptar y conservar el texto después de darle formato. Estas características ofrecen una compatibilidad fundamental para los distintos requisitos de representación de texto en cada uno de los siguientes escenarios.

  • Presentación en pantalla de documentos de formato fijo.

  • Escenarios de impresión.

    • Lenguaje de marcado de aplicaciones extensible (XAML) como lenguaje de impresora del dispositivo.

    • Escritor de documentos XPS de Microsoft.

    • Controladores de impresora anteriores: salida de aplicaciones Win32 al formato fijo.

    • Formato de cola de impresión.

  • Representación de documentos de formato fijo, incluidos clientes de versiones anteriores de Windows y otros dispositivos informáticos.

Nota

Glyphs y GlyphRun están diseñados para escenarios de presentación e impresión de documentos de formato fijo. WPF proporciona varios elementos para escenarios generales de diseño e interfaz de usuario (UI), como Label y TextBlock. Para obtener más información sobre los escenarios de diseño e interfaz de usuario, consulte Tipografía en WPF.

En los ejemplos siguientes se muestra cómo definir las propiedades de un objeto Glyphs en XAML. En los ejemplos se supone que las fuentes Arial, Courier New y Times New Roman están instaladas en la carpeta C:\WINDOWS\Fonts del equipo local.

<!-- The example shows how to use a Glyphs object. -->
<Page
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  >

   <StackPanel Background="PowderBlue">

      <Glyphs
         FontUri             = "C:\WINDOWS\Fonts\TIMES.TTF"
         FontRenderingEmSize = "100"
         StyleSimulations    = "BoldSimulation"
         UnicodeString       = "Hello World!"
         Fill                = "Black"
         OriginX             = "100"
         OriginY             = "200"
      />

   </StackPanel>
</Page>

Usar DrawGlyphRun

Si tiene un control personalizado y quiere representar glifos, utilice el método DrawGlyphRun.

WPF también proporciona servicios de nivel inferior para formatear texto personalizado mediante el uso del objeto FormattedText. La forma más eficiente de representar texto en Windows Presentation Foundation (WPF) es generando contenido de texto a nivel de glifo usando Glyphs y GlyphRun. Sin embargo, el coste de esta eficiencia es la pérdida del formato de texto enriquecido fácil de usar, que son características integradas de los controles de Windows Presentation Foundation (WPF), como TextBlock y FlowDocument.

Objeto FormattedText

El objeto FormattedText permite dibujar texto de varias líneas, en el que se puede dar formato individual a cada carácter del texto. Para obtener más información, consulte Dibujar texto con formato.

Para crear texto formateado, llame al constructor FormattedText para crear un objeto FormattedText. Una vez que haya creado la cadena inicial de texto con formato, podrá aplicar una gama de estilos de formato. Si su aplicación quiere implementar su propio diseño, entonces el objeto FormattedText es mejor opción que usar un control, como TextBlock. Para más información sobre el objeto FormattedText, vea Dibujar texto con formato .

El objeto FormattedText proporciona una capacidad de formato de texto de bajo nivel. Puede aplicar varios estilos de formato a uno o más caracteres. Por ejemplo, puede llamar a los métodos SetFontSize y SetForegroundBrush para cambiar el formato de los cinco primeros caracteres del texto.

El siguiente ejemplo de código crea un objeto FormattedText y lo representa.

protected override void OnRender(DrawingContext drawingContext)
{
    string testString = "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor";

    // Create the initial formatted text string.
    FormattedText formattedText = new FormattedText(
        testString,
        CultureInfo.GetCultureInfo("en-us"),
        FlowDirection.LeftToRight,
        new Typeface("Verdana"),
        32,
        Brushes.Black);

    // Set a maximum width and height. If the text overflows these values, an ellipsis "..." appears.
    formattedText.MaxTextWidth = 300;
    formattedText.MaxTextHeight = 240;

    // Use a larger font size beginning at the first (zero-based) character and continuing for 5 characters.
    // The font size is calculated in terms of points -- not as device-independent pixels.
    formattedText.SetFontSize(36 * (96.0 / 72.0), 0, 5);

    // Use a Bold font weight beginning at the 6th character and continuing for 11 characters.
    formattedText.SetFontWeight(FontWeights.Bold, 6, 11);

    // Use a linear gradient brush beginning at the 6th character and continuing for 11 characters.
    formattedText.SetForegroundBrush(
                            new LinearGradientBrush(
                            Colors.Orange,
                            Colors.Teal,
                            90.0),
                            6, 11);

    // Use an Italic font style beginning at the 28th character and continuing for 28 characters.
    formattedText.SetFontStyle(FontStyles.Italic, 28, 28);

    // Draw the formatted text string to the DrawingContext of the control.
    drawingContext.DrawText(formattedText, new Point(10, 0));
}
Protected Overrides Sub OnRender(ByVal drawingContext As DrawingContext)
    Dim testString As String = "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor"

    ' Create the initial formatted text string.
    Dim formattedText As New FormattedText(testString, CultureInfo.GetCultureInfo("en-us"), FlowDirection.LeftToRight, New Typeface("Verdana"), 32, Brushes.Black)

    ' Set a maximum width and height. If the text overflows these values, an ellipsis "..." appears.
    formattedText.MaxTextWidth = 300
    formattedText.MaxTextHeight = 240

    ' Use a larger font size beginning at the first (zero-based) character and continuing for 5 characters.
    ' The font size is calculated in terms of points -- not as device-independent pixels.
    formattedText.SetFontSize(36 * (96.0 / 72.0), 0, 5)

    ' Use a Bold font weight beginning at the 6th character and continuing for 11 characters.
    formattedText.SetFontWeight(FontWeights.Bold, 6, 11)

    ' Use a linear gradient brush beginning at the 6th character and continuing for 11 characters.
    formattedText.SetForegroundBrush(New LinearGradientBrush(Colors.Orange, Colors.Teal, 90.0), 6, 11)

    ' Use an Italic font style beginning at the 28th character and continuing for 28 characters.
    formattedText.SetFontStyle(FontStyles.Italic, 28, 28)

    ' Draw the formatted text string to the DrawingContext of the control.
    drawingContext.DrawText(formattedText, New Point(10, 0))
End Sub

Controles FlowDocument, TextBlock y Label

WPF incluye varios controles para dibujar texto en la pantalla. Cada control se destina a un escenario diferente y tiene su propia lista de características y limitaciones.

FlowDocument afecta al rendimiento más que TextBlock o Label

En general, el elemento TextBlock debe usarse cuando se necesita compatibilidad de texto limitada, como una frase breve en una interfaz de usuario (UI). Label puede usarse cuando se necesita una compatibilidad de texto mínima. El elemento FlowDocument es un contenedor para documentos re-fluibles que soportan una presentación rica en contenido, y por lo tanto, tiene un mayor impacto en el rendimiento que el uso de los controles TextBlock o Label.

Para obtener más información sobre FlowDocument, vea Información general sobre documentos dinámicos.

Evitar el uso de TextBlock en FlowDocument

El elemento TextBlock se deriva de UIElement. El elemento Run se deriva de TextElement, que es menos costoso de utilizar que un objeto derivado de UIElement. Cuando sea posible, utilice Run en lugar de TextBlock para mostrar el contenido del texto en un FlowDocument.

En el ejemplo de marcado siguiente se muestran dos maneras de establecer contenido de texto dentro de FlowDocument:

<FlowDocument>

  <!-- Text content within a Run (more efficient). -->
  <Paragraph>
    <Run>Line one</Run>
  </Paragraph>

  <!-- Text content within a TextBlock (less efficient). -->
  <Paragraph>
    <TextBlock>Line two</TextBlock>
  </Paragraph>

</FlowDocument>

Evitar el uso de ejecución para establecer propiedades de texto

En general, el uso de un Run dentro de un TextBlock es más intensivo en cuanto a rendimiento que no usar un objeto Run explícito. Si usa un Run para establecer las propiedades del texto, establezca esas propiedades directamente en TextBlock en su lugar.

En el ejemplo de marcado siguiente se muestran estas dos maneras de establecer una propiedad de texto. En este caso, la propiedad FontWeight:

<!-- Run is used to set text properties. -->
<TextBlock>
  <Run FontWeight="Bold">Hello, world</Run>
</TextBlock>

<!-- TextBlock is used to set text properties, which is more efficient. -->
<TextBlock FontWeight="Bold">
  Hello, world
</TextBlock>

La siguiente tabla muestra el coste de mostrar 1000 objetos TextBlock con y sin un Run explícito.

Tipo TextBlock Tiempo de creación (ms) Tiempo de representación (ms)
Propiedades de texto de configuración de ejecución 146 540
Propiedades de texto de configuración de TextBlock 43 453

Evitar el enlace de datos a la propiedad Label.Content

Imagina un escenario en el que tiene un objeto Label que se actualiza frecuentemente desde un origen String. Al vincular los datos de la propiedad Label del elemento Content al objeto origen String, se puede experimentar un bajo rendimiento. Cada vez que se actualiza el origen String, el antiguo objeto String se descarta y se vuelve a crear un nuevo String, ya que un objeto String es inmutable, no puede modificarse. Esto, a su vez, hace que el ContentPresenter del objeto Label descarte su antiguo contenido y regenere el nuevo contenido para mostrar el nuevo String.

La solución a este problema es sencilla. Si Label no está configurado con un valor ContentTemplate personalizado, sustituya Label por un TextBlock y vincule su propiedad Text a la cadena de origen.

Propiedad enlazada a datos Tiempo de actualización (ms)
Label.Content 835
TextBlock.Text 242

El objeto Hyperlink es un elemento de contenido dinámico de nivel insertado que permite hospedar hipervínculos dentro del contenido dinámico.

Puede optimizar el uso de múltiples elementos Hyperlink agrupándolos dentro del mismo TextBlock. Esto ayuda a minimizar el número de objetos que crea en la aplicación. Por ejemplo, es posible que quiera mostrar varios hipervínculos, como los siguientes:

Página principal MSN | Mi MSN

En el ejemplo de marcado siguiente se muestran varios elementos TextBlock que se usan para mostrar los hipervínculos:

<!-- Hyperlinks in separate TextBlocks. -->
<TextBlock>
  <Hyperlink TextDecorations="None" NavigateUri="http://www.msn.com">MSN Home</Hyperlink>
</TextBlock>

<TextBlock Text=" | "/>

<TextBlock>
  <Hyperlink TextDecorations="None" NavigateUri="http://my.msn.com">My MSN</Hyperlink>
</TextBlock>

En el ejemplo de marcado siguiente se muestra una manera más eficaz de mostrar los hipervínculos, pero, esta vez, con un solo objeto TextBlock:

<!-- Hyperlinks combined in the same TextBlock. -->
<TextBlock>
  <Hyperlink TextDecorations="None" NavigateUri="http://www.msn.com">MSN Home</Hyperlink>
  
  <Run Text=" | " />
  
  <Hyperlink TextDecorations="None" NavigateUri="http://my.msn.com">My MSN</Hyperlink>
</TextBlock>

Un objeto TextDecoration es un adorno visual que se puede agregar al texto. Sin embargo, puede mejorar el rendimiento al crear instancias. Si hace un uso extensivo de los elementos Hyperlink, considere la posibilidad de mostrar un subrayado solo cuando se active un evento, como el evento MouseEnter. Para obtener más información, consulte Especificar el subrayado de un hipervínculo.

La siguiente imagen muestra cómo el evento MouseEnter activa el hipervínculo subrayado:

Hipervínculos que muestran TextDecorations

En el ejemplo de marcado siguiente se muestra un elemento Hyperlink definido con y sin subrayado:

<!-- Hyperlink with default underline. -->
<Hyperlink NavigateUri="http://www.msn.com">
  MSN Home
</Hyperlink>

<Run Text=" | " />

<!-- Hyperlink with no underline. -->
<Hyperlink Name="myHyperlink" TextDecorations="None"
           MouseEnter="OnMouseEnter"
           MouseLeave="OnMouseLeave"
           NavigateUri="http://www.msn.com">
  My MSN
</Hyperlink>

En la siguiente tabla se muestra el costo de rendimiento de mostrar 1000 elementos Hyperlink con y sin subrayado.

Hipervínculo Tiempo de creación (ms) Tiempo de representación (ms)
Con subrayado 289 1130
Sin subrayado 299 776

Características de formato de texto

WPF proporciona servicios de formato de texto enriquecido, como la división de palabras automática. Estos servicios pueden afectar al rendimiento de la aplicación y solo deben usarse cuando sea necesario.

Evitar el uso innecesario de la división de palabras

La separación automática de guiones encuentra puntos de interrupción de guiones para las líneas de texto, y permite posiciones de interrupción adicionales para las líneas en los objetos TextBlock y FlowDocument. De forma predeterminada, la característica de división de palabras automática está deshabilitada en estos objetos. Puede habilitarla si establece la propiedad IsHyphenationEnabled del objeto en true. Sin embargo, si se habilita esta característica, WPF inicia la interoperabilidad del Modelo de objetos componentes (COM), lo que puede afectar el rendimiento de la aplicación. Se recomienda que no se la división de palabras automática a menos que lo necesite.

Usar figuras con cuidado

Un elemento Figure representa una parte del contenido dinámico que puede tener una posición absoluta dentro de una página de contenido. En algunos casos, un Figure puede hacer que toda una página se reformatee automáticamente si su posición colisiona con el contenido que ya se ha maquetado. Puede minimizar la posibilidad de un reformateo innecesario agrupando los elementos Figure uno al lado del otro, o declarándolos cerca de la parte superior del contenido en un escenario de tamaño de página fijo.

Párrafo óptimo

La característica de párrafo óptimo del objeto FlowDocument dispone los párrafos para que el espacio en blanco se distribuya lo más uniformemente posible. De forma predeterminada, la característica de párrafo óptimo está deshabilitada. Puede habilitar esta función estableciendo la propiedad IsOptimalParagraphEnabled del objeto como true. Sin embargo, habilitar esta característica afecta al rendimiento de la aplicación. Se recomienda que no use la característica de párrafo óptimo a menos que la necesite.

Vea también