Formatação avançada de texto
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 aspetos 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 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çado.
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 Documents in WPF.
Formatação avançada de texto
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 manipular a apresentação do texto, que inclui seu tipo de letra, tamanho e cor. Em circunstâncias normais, esses controles podem lidar com a maioria da apresentação de texto em seu aplicativo. No entanto, alguns cenários avançados requerem o controle do armazenamento de texto, bem como a apresentação de texto. 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, TextFormatter, cria linhas de texto a serem usadas para apresentação. Isso é conseguido iniciando o processo de formatação de linha e chamando a função FormatLinedo formatador de texto. O formatador de texto recupera segmentos de texto do seu repositório de texto chamando o método GetTextRun do repositório. Os objetos TextRun são então formados em objetos TextLine 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 diferentes formatos de caracteres de texto e estilos de parágrafo, e inclui suporte para layout de texto internacional.
Ao contrário de uma API de texto tradicional, o TextFormatter interage com um cliente de layout de texto através de um conjunto de métodos de chamada de retorno. Ele requer que o cliente forneça esses métodos em uma implementação da classe TextSource. O diagrama a seguir ilustra a interação de layout de texto entre o aplicativo cliente e 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 método Create. Esse método cria uma instância do formatador de texto e define os valores máximos de altura e largura da linha. Assim que uma instância do formatador de texto é criada, o processo de criação de linha é iniciado chamando o método FormatLine. TextFormatter chama a fonte de texto para recuperar os parâmetros de texto e formatação para os segmentos de texto que formam uma linha.
No exemplo a seguir, o processo de formatação de um armazenamento de texto é mostrado. O objeto TextFormatter é usado para recuperar linhas de texto do armazenamento de texto e, em seguida, formatar a linha de texto para desenhar 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 armazenamento de texto do cliente
Quando você estende o mecanismo de formatação de texto, é necessário implementar e gerenciar todos os aspetos do armazenamento de texto. Esta não é uma tarefa trivial. O armazém de texto é responsável por controlar propriedades de fragmentos de texto, propriedades de parágrafo, objetos incorporados e outros conteúdos semelhantes. Também fornece ao formatador de texto objetos TextRun individuais que o formatador de texto usa para criar objetos TextLine.
Para lidar com 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 utiliza para recuperar segmentos de texto do armazenamento de texto. GetTextRun é o método utilizado pelo formatador de texto para recuperar segmentos de texto usados na formatação de linhas. A chamada para GetTextRun é repetidamente feita pelo formatador de texto até que uma das seguintes condições ocorra:
Um TextEndOfLine ou uma subclasse é retornado.
A largura acumulada dos segmentos de texto excede a largura máxima de linha especificada quer na chamada para criar o formatador de texto, quer na chamada para o método FormatLine do formatador de 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 armazenamento de texto. A sua implementação de TextSource fornece ao formatador de texto os objetos TextRun e as propriedades para formatar as execuções de texto. Essa interação é manipulada pelo método GetTextRun, que é chamado pelo formatador de texto.
A tabela a seguir mostra alguns dos objetos TextRun predefinidos.
Tipo TextRun | Utilização |
---|---|
TextCharacters | A execução de texto especializada usada para passar uma representação de glifos de caracteres de volta para o formatador de texto. |
TextEmbeddedObject | O segmento de texto especializado utilizado para fornecer conteúdo em que a medição, o teste de colisão e o desenho são realizados na íntegra, como um botão ou imagem dentro do texto. |
TextEndOfLine | O trecho de texto especializado usado para marcar o final de uma linha. |
TextEndOfParagraph | O formato de texto especializado usado 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 de TextModifier anterior. |
TextHidden | A execução de texto especializado usada para marcar um intervalo de caracteres ocultos. |
TextModifier | A execução de texto especializada usada para modificar propriedades de execuções de texto dentro do seu escopo. O escopo estende-se à próxima execução de texto correspondente TextEndOfSegment ou à próxima TextEndOfParagraph. |
Qualquer um dos objetos TextRun predefinidos pode ser subclassificado. Isso permite que sua fonte de texto forneça ao formatador de texto execuções de texto que incluem dados personalizados.
O exemplo a seguir demonstra um método GetTextRun. 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 armazenamento de texto fornece as mesmas propriedades de texto para todo o texto. Sistemas de armazenamento de texto avançados precisariam implementar a sua própria gestão de span para permitir que caracteres individuais tivessem propriedades diferentes.
Especificando propriedades de formatação
TextRun objetos são formatados através de propriedades fornecidas pelo repositório de texto. Essas propriedades vêm em dois tipos, TextParagraphProperties e TextRunProperties. TextParagraphProperties manipular propriedades que incluem parágrafos, como TextAlignment e FlowDirection. TextRunProperties são propriedades que podem ser diferentes para cada texto executado em um parágrafo, como pincel de primeiro plano, Typefacee tamanho da fonte. Para implementar parágrafos personalizados e tipos de propriedade de execução de texto personalizado, seu aplicativo deve criar classes que derivam de TextParagraphProperties e TextRunProperties respectivamente.
Ver também
.NET Desktop feedback