Compartilhar via


Formatação de texto avançada

O Windows Presentation Foundation (WPF) fornece um conjunto robusto de APIs para incluir texto em seu aplicativo. As APIs de layout e interface do usuário (UI), como TextBlock, fornecem os elementos mais comuns e de uso geral para apresentação de texto. As APIs de desenho, como GlyphRunDrawing e FormattedText, fornecem um meio para incluir texto formatado em desenhos. No nível mais avançado, o WPF fornece um mecanismo de formatação de texto extensível para controlar todos os aspectos da apresentação de texto, como gerenciamento de armazenamento de texto, gerenciamento de formatação de execução de texto e gerenciamento de objetos incorporados.

Este tópico fornece uma introdução à formatação de texto do WPF. Ele se concentra na implementação do cliente e no uso do mecanismo de formatação de texto WPF.

Observação

Todos os exemplos de código neste documento podem ser encontrados no Exemplo de formatação de texto avançada.

Pré-requisitos

Este tópico pressupõe que você esteja familiarizado com as APIs de nível superior usadas para apresentação de texto. A maioria dos cenários de usuário não exigirá as APIs avançadas de formatação de texto discutidas neste tópico. Para obter uma introdução às diferentes APIs de texto, consulte Documentos no WPF.

Formatação de texto avançada

O layout de texto e os controles de interface do usuário no WPF fornecem propriedades de formatação que permitem que você inclua facilmente texto formatado em seu aplicativo. Esses controles expõem várias propriedades para lidar com a apresentação do texto, que inclui sua face de tipos, tamanho e cor. Em circunstâncias normais, esses controles podem lidar com a maior parte da apresentação do texto em seu aplicativo. No entanto, alguns cenários avançados exigem o controle do armazenamento de texto, bem como a apresentação de texto. O WPF fornece um mecanismo de formatação de texto extensível para essa finalidade.

Os recursos avançados de formatação de texto encontrados no WPF consistem em um mecanismo de formatação de texto, um armazenamento de texto, execuções de texto e propriedades de formatação. O mecanismo de formatação de texto, , TextFormattercria linhas de texto a serem usadas para apresentação. Isso é obtido iniciando o processo de formatação de linha e chamando o formatador de FormatLinetexto . O formatador de texto recupera execuções de texto do seu armazenamento de texto chamando o método do GetTextRun armazenamento. Os TextRun objetos são então formados em TextLine objetos pelo formatador de texto e entregues ao seu aplicativo para inspeção ou exibição.

Usando o formatador de texto

TextFormatter é o mecanismo de formatação de texto WPF e fornece serviços para formatação e quebra de linhas de texto. O formatador de texto pode lidar com formatos de caracteres de texto diferentes e estilos de parágrafo e inclui suporte para o layout de texto internacional.

Ao contrário de uma API de texto tradicional, o TextFormatter interage com um cliente de layout de texto por meio de um conjunto de métodos de retorno de chamada. Ele requer que o cliente forneça esses métodos em uma implementação da TextSource classe. O diagrama a seguir ilustra a interação de layout de texto entre o aplicativo cliente e TextFormattero .

Diagram of text layout client and TextFormatter

O formatador de texto é usado para recuperar linhas de texto formatadas do armazenamento de texto, que é uma implementação do TextSource. Isso é feito criando primeiro uma instância do formatador de texto usando o Create método. Esse método cria uma instância de formatador de texto e define a altura de linha máxima e os valores de largura. Assim que uma instância do formatador de texto é criada, o processo de criação de linha é iniciado chamando o FormatLine método. TextFormatter Chama de volta à fonte de texto para recuperar o texto e os parâmetros de formatação para as execuções de texto que formam uma linha.

No exemplo a seguir, o processo de formatação de um repositório de texto é mostrado. O TextFormatter objeto é usado para recuperar linhas de texto do armazenamento de texto e, em seguida, formatar a linha de texto para desenho no 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

Implementando o repositório de texto do cliente

Ao estender o mecanismo de formatação de texto, é necessário implementar e gerenciar todos os aspectos do repositório de texto. Isso não é uma tarefa trivial. O repositório de texto é responsável por acompanhar propriedades de execução de texto, propriedades de parágrafo, objetos incorporados e outros conteúdos semelhantes. Ele também fornece ao formatador de texto objetos individuais TextRun que o formatador de texto usa para criar TextLine objetos.

Para manipular a virtualização do armazenamento de texto, o armazenamento de texto deve ser derivado de TextSource. TextSource Define o método que o formatador de texto usa para recuperar execuções de texto do armazenamento de texto. GetTextRun é o método usado pelo formatador de texto para recuperar execuções de texto usadas na formatação de linha. A chamada para GetTextRun é feita repetidamente pelo formatador de texto até que uma das seguintes condições ocorra:

  • Uma TextEndOfLine ou uma subclasse é retornada.

  • A largura acumulada das execuções de texto excede a largura máxima da linha especificada na chamada para criar o formatador de texto ou na chamada para o método do formatador de FormatLine texto.

  • Uma sequência de nova linha Unicode, como "CF", "LF" ou "CRLF", é retornada.

Fornecendo execuções de texto

O núcleo do processo de formatação de texto é a interação entre o formatador de texto e o repositório de texto. Sua implementação de fornece ao formatador de TextSource texto os TextRun objetos e as propriedades com as quais formatar o texto é executado. Essa interação é manipulada GetTextRun pelo método, que é chamado pelo formatador de texto.

A tabela a seguir mostra alguns dos objetos predefinidos TextRun .

Tipo de TextRun Uso
TextCharacters A execução de texto especializado para passar uma representação de glifos de caractere de volta para o formatador de texto.
TextEmbeddedObject A execução de texto especializado usada para fornecer conteúdo no qual a medição, o teste de hit e o desenho são feitos no todo, como um botão ou imagem dentro do texto.
TextEndOfLine A execução de texto especializado usada para marcar o final de uma linha.
TextEndOfParagraph A execução de texto especializado usada para marcar o final de um parágrafo.
TextEndOfSegment A execução de texto especializado usada para marcar o final de um segmento, como para encerrar o escopo afetado por uma execução anterior TextModifier .
TextHidden A execução de texto especializado usada para marcar um intervalo de caracteres ocultos.
TextModifier A execução de texto especializado usada para modificar as propriedades das execuções de texto nesse escopo. O escopo se estende para a próxima execução de texto correspondente TextEndOfSegment ou para a próxima TextEndOfParagraph.

Qualquer um dos objetos predefinidos TextRun pode ser subclassificado. Isso permite que a fonte de texto forneça ao formatador de texto as execuções de texto que incluem dados personalizados.

O exemplo a seguir demonstra um GetTextRun método. Esse armazenamento de texto retorna TextRun objetos ao formatador de texto para processamento.

// 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

Observação

Neste exemplo, o repositório de texto fornece as mesmas propriedades de texto para todo o texto. Os armazenamentos avançados de texto precisariam implementar seus próprios gerenciamentos de período para permitir caracteres individuais com propriedades diferentes.

Especificando propriedades de formatação

TextRun Os objetos são formatados usando propriedades fornecidas pelo armazenamento de texto. Essas propriedades vêm em dois tipos TextParagraphProperties e TextRunProperties. TextParagraphProperties manipular propriedades de inclusão de parágrafo, como TextAlignment e FlowDirection. TextRunProperties são propriedades que podem ser diferentes para cada texto executado em um parágrafo, como pincel Typefacede primeiro plano e tamanho da fonte. Para implementar tipos de propriedade de execução de parágrafo personalizado e texto personalizado, seu aplicativo deve criar classes que derivam de TextParagraphProperties e TextRunProperties respectivamente.

Confira também