Compartir a través de


Formato de texto avanzado

Windows Presentation Foundation (WPF) proporciona un conjunto sólido de API para incluir texto en la aplicación. Las API de diseño e interfaz de usuario (UI), como TextBlock, proporcionan los elementos de uso general y más comunes para la presentación de texto. Las API de dibujo, como GlyphRunDrawing y FormattedText, proporcionan un medio para incluir texto con formato en dibujos. En el nivel más avanzado, WPF proporciona un motor de formato de texto extensible para controlar todos los aspectos de la presentación de texto, como la administración del almacén de texto, la administración de formatos de ejecución de texto y la administración de objetos incrustados.

En este tema se proporciona una introducción al formato de texto wpF. Se centra en la implementación de cliente y el uso del motor de formato de texto de WPF.

Nota:

Todos los ejemplos de código de este documento se pueden encontrar en el ejemplo de formato de texto avanzado.

Prerrequisitos

En este tema se supone que está familiarizado con las API de nivel superior que se usan para la presentación de texto. La mayoría de los escenarios de usuario no requerirán las API de formato de texto avanzadas que se describen en este tema. Para obtener una introducción a las distintas API de texto, vea Documentos en WPF.

Formato de texto avanzado

Los controles de diseño de texto y interfaz de usuario de WPF proporcionan propiedades de formato que permiten incluir fácilmente texto con formato en la aplicación. Estos controles exponen una serie de propiedades para controlar la presentación del texto, que incluye su tipo de letra, tamaño y color. En circunstancias normales, estos controles pueden controlar la mayoría de la presentación de texto en la aplicación. Sin embargo, algunos escenarios avanzados requieren el control del almacenamiento de texto, así como la presentación de texto. WPF proporciona un motor de formato de texto extensible para este propósito.

Las características avanzadas de formato de texto que se encuentran en WPF constan de un motor de formato de texto, un almacén de texto, ejecuciones de texto y propiedades de formato. El motor de formato de texto, TextFormatter, crea líneas de texto que se usarán para la presentación. Esto se logra iniciando el proceso de formato de línea y llamando al formateador de texto FormatLine. El formateador de texto recupera los fragmentos de texto del almacén de texto llamando al método GetTextRun del almacén. A continuación, los TextRun objetos se forman en TextLine objetos mediante el formateador de texto y se proporcionan a la aplicación para su inspección o visualización.

Uso del formateador de texto

TextFormatter es el motor de formato de texto de WPF y proporciona servicios para dar formato y romper líneas de texto. El formateador de texto puede controlar diferentes formatos de caracteres de texto y estilos de párrafo, e incluye compatibilidad con el diseño de texto internacional.

A diferencia de una API de texto tradicional, el TextFormatter interactúa con un cliente de diseño de texto a través de un conjunto de métodos de devolución de llamada. Requiere que el cliente proporcione estos métodos en una implementación de la TextSource clase . En el diagrama siguiente se muestra la interacción de diseño de texto entre la aplicación cliente y TextFormatter.

Diagrama del cliente de diseño de texto y TextFormatter

El formateador de texto se usa para recuperar líneas de texto formateadas del almacén de texto, que es una implementación de TextSource. Para ello, primero se crea una instancia del formateador de texto mediante el Create método . Este método crea una instancia del formateador de texto y establece los valores máximos de alto y ancho de línea. En cuanto se crea una instancia del formateador de texto, el proceso de creación de líneas se inicia llamando al FormatLine método . TextFormatter vuelve a llamar al origen de texto para recuperar el texto y los parámetros de formato de los fragmentos de texto que forman una línea.

En el ejemplo siguiente, se muestra el proceso de dar formato a un almacén de texto. El objeto TextFormatter se utiliza para obtener líneas de texto del almacén de texto y luego formatearlas para dibujarlas en el DrawingContext.

// Create a DrawingGroup object for storing formatted text.
textDest = new DrawingGroup();
DrawingContext dc = textDest.Open();

// Update the text store.
_textStore.Text = textToFormat.Text;
_textStore.FontRendering = _currentRendering;

// Create a TextFormatter object.
TextFormatter formatter = TextFormatter.Create();

// Format each line of text from the text store and draw it.
while (textStorePosition < _textStore.Text.Length)
{
   // Create a textline from the text store using the TextFormatter object.
   using (TextLine myTextLine = formatter.FormatLine(
       _textStore,
       textStorePosition,
       96*6,
       new GenericTextParagraphProperties(_currentRendering),
       null))
   {
       // Draw the formatted text into the drawing context.
       myTextLine.Draw(dc, linePosition, InvertAxes.None);

       // Update the index position in the text store.
       textStorePosition += myTextLine.Length;

       // Update the line position coordinate for the displayed line.
       linePosition.Y += myTextLine.Height;
   }
}

// Persist the drawn text content.
dc.Close();

// Display the formatted text in the DrawingGroup object.
myDrawingBrush.Drawing = textDest;
' Create a DrawingGroup object for storing formatted text.
textDest = New DrawingGroup()
Dim dc As DrawingContext = textDest.Open()

' Update the text store.
_textStore.Text = textToFormat.Text
_textStore.FontRendering = _currentRendering

' Create a TextFormatter object.
Dim formatter As TextFormatter = TextFormatter.Create()

' Format each line of text from the text store and draw it.
Do While textStorePosition < _textStore.Text.Length
   ' Create a textline from the text store using the TextFormatter object.
   Using myTextLine As TextLine = formatter.FormatLine(_textStore, textStorePosition, 96*6, New GenericTextParagraphProperties(_currentRendering), Nothing)
       ' Draw the formatted text into the drawing context.
       myTextLine.Draw(dc, linePosition, InvertAxes.None)

       ' Update the index position in the text store.
       textStorePosition += myTextLine.Length

       ' Update the line position coordinate for the displayed line.
       linePosition.Y += myTextLine.Height
   End Using
Loop

' Persist the drawn text content.
dc.Close()

' Display the formatted text in the DrawingGroup object.
myDrawingBrush.Drawing = textDest

Implementación del almacén de texto de cliente

Al ampliar el motor de formato de texto, es necesario implementar y administrar todos los aspectos del almacén de texto. Esto no es una tarea trivial. El almacén de texto es responsable del seguimiento de propiedades de ejecución de texto, propiedades de párrafo, objetos incrustados y otro contenido similar. También proporciona al formateador de texto objetos individuales TextRun que este usa para crear objetos TextLine.

Para controlar la virtualización del almacén de texto, el almacén de texto debe derivarse de TextSource. TextSource define el método que utiliza el formateador de texto para obtener segmentos de texto del almacén de texto. GetTextRun es el método utilizado por el formateador de texto para recuperar fragmentos de texto utilizados en la formateo de líneas. El formateador de texto realiza repetidamente la llamada a GetTextRun hasta que se produce una de las condiciones siguientes:

  • Se devuelve una TextEndOfLine o una subclase.

  • El ancho acumulado de las corridas de texto supera el ancho máximo de línea especificado ya sea en la llamada para crear el formateador de texto o en la llamada al método FormatLine del formateador de texto.

  • Se devuelve una secuencia de nueva línea Unicode, como "CF", "LF" o "CRLF".

Proporcionar ejecuciones de texto

El núcleo del proceso de formato de texto es la interacción entre el formateador de texto y el almacén de texto. Tu implementación de TextSource proporciona al formateador de texto los objetos TextRun y las propiedades con las que se formatearán las ejecuciones de texto. Esta interacción es manejada por el método GetTextRun, al que llama el formateador de texto.

En la tabla siguiente se muestran algunos de los objetos predefinidos TextRun .

Tipo TextRun Uso
TextCharacters El fragmento de texto especializado utilizado para devolver una representación de los glifos de caracteres al formateador de texto.
TextEmbeddedObject El texto especializado que se usa para proporcionar contenido en el que la medición, las pruebas de impacto y el dibujo se realizan completamente, como un botón o una imagen dentro del texto.
TextEndOfLine Bloque de texto especializado utilizado para marcar el final de una línea.
TextEndOfParagraph Texto especializado utilizado para marcar el final de un párrafo.
TextEndOfSegment La cadena de texto especializada utilizada para marcar el final de un segmento, por ejemplo, para terminar el ámbito afectado por una ejecución anterior TextModifier.
TextHidden Texto especializado utilizado para marcar un rango de caracteres ocultos.
TextModifier El fragmento de texto especializado usado para modificar las propiedades de los fragmentos de texto en su ámbito. El ámbito se extiende a la siguiente ejecución de texto coincidente TextEndOfSegment o al siguiente TextEndOfParagraph.

Cualquiera de los objetos predefinidos TextRun se puede subclasizar. Esto permite que el origen de texto proporcione al formateador de texto fragmentos de texto que incluyan datos personalizados.

En el ejemplo siguiente se muestra un GetTextRun método . Este almacén de texto devuelve TextRun objetos al formateador de texto para su procesamiento.

// Used by the TextFormatter object to retrieve a run of text from the text source.
public override TextRun GetTextRun(int textSourceCharacterIndex)
{
   // Make sure text source index is in bounds.
   if (textSourceCharacterIndex < 0)
      throw new ArgumentOutOfRangeException("textSourceCharacterIndex", "Value must be greater than 0.");
   if (textSourceCharacterIndex >= _text.Length)
   {
      return new TextEndOfParagraph(1);
   }

   // Create TextCharacters using the current font rendering properties.
   if (textSourceCharacterIndex < _text.Length)
   {
      return new TextCharacters(
         _text,
         textSourceCharacterIndex,
         _text.Length - textSourceCharacterIndex,
         new GenericTextRunProperties(_currentRendering));
   }

   // Return an end-of-paragraph if no more text source.
   return new TextEndOfParagraph(1);
}
' Used by the TextFormatter object to retrieve a run of text from the text source.
Public Overrides Function GetTextRun(ByVal textSourceCharacterIndex As Integer) As TextRun
   ' Make sure text source index is in bounds.
   If textSourceCharacterIndex < 0 Then
      Throw New ArgumentOutOfRangeException("textSourceCharacterIndex", "Value must be greater than 0.")
   End If
   If textSourceCharacterIndex >= _text.Length Then
      Return New TextEndOfParagraph(1)
   End If

   ' Create TextCharacters using the current font rendering properties.
   If textSourceCharacterIndex < _text.Length Then
      Return New TextCharacters(_text, textSourceCharacterIndex, _text.Length - textSourceCharacterIndex, New GenericTextRunProperties(_currentRendering))
   End If

   ' Return an end-of-paragraph if no more text source.
   Return New TextEndOfParagraph(1)
End Function

Nota:

En este ejemplo, el almacén de texto proporciona las mismas propiedades de texto a todo el texto. Los almacenes de texto avanzados necesitarían implementar su propia administración de intervalos para permitir que los caracteres individuales tengan propiedades diferentes.

Especificar propiedades de formato

TextRun Los objetos tienen formato mediante las propiedades proporcionadas por el almacén de texto. Estas propiedades se incluyen en dos tipos, TextParagraphProperties y TextRunProperties. TextParagraphProperties controle las propiedades inclusivas de párrafo, como TextAlignment y FlowDirection. TextRunProperties son propiedades que pueden ser diferentes para cada ejecución de texto dentro de un párrafo, como el pincel de primer plano, Typefacey el tamaño de fuente. Para implementar tipos de propiedades de párrafo personalizado y de ejecución de texto personalizado, la aplicación debe crear clases que deriven de TextParagraphProperties y TextRunProperties respectivamente.

Consulte también