Formattazione avanzata del testo
Windows Presentation Foundation (WPF) offre un set affidabile di API per includere testo nell'applicazione. Le API di layout e interfaccia utente, ad esempio TextBlock, forniscono gli elementi più comuni e di uso generico per la presentazione di testo. Le API di disegno, ad esempio GlyphRunDrawing e FormattedText, forniscono un mezzo per includere testo formattato nei disegni. A livello più avanzato, WPF offre un motore di formattazione del testo estendibile per controllare ogni aspetto della presentazione di testo, ad esempio la gestione dell'archivio testo, la gestione della formattazione delle esecuzioni di testo e la gestione degli oggetti incorporata.
In questo argomento viene fornita un'introduzione alla formattazione del testo WPF. Si concentra sull'implementazione client e sull'uso del motore di formattazione del testo WPF.
Nota
Tutti gli esempi di codice all'interno di questo documento sono disponibili in Esempio di formattazione del testo avanzato.
Prerequisiti
In questo argomento si presuppone che l'utente abbia familiarità con le API di livello superiore usate per la presentazione di testo. La maggior parte degli scenari utente non richiederà le API avanzate di formattazione del testo descritte in questo argomento. Per un'introduzione alle diverse API di testo, vedere Documenti in WPF.
Formattazione avanzata del testo
I controlli layout del testo e dell'interfaccia utente in WPF forniscono proprietà di formattazione che consentono di includere facilmente testo formattato nell'applicazione. Questi controlli espongono una serie di proprietà per gestire la presentazione del testo, che include il carattere tipografico, le dimensioni e il colore. In circostanze normali, questi controlli possono gestire la maggior parte della presentazione di testo nell'applicazione. Tuttavia, alcuni scenari avanzati richiedono il controllo dell'archiviazione del testo e della presentazione del testo. WPF fornisce un motore di formattazione del testo estendibile a questo scopo.
Le funzionalità avanzate di formattazione del testo disponibili in WPF sono costituite da un motore di formattazione del testo, da un archivio di testo, da esecuzioni di testo e da proprietà di formattazione. Il motore di formattazione del testo, TextFormatter, crea righe di testo da utilizzare per la presentazione. A tale scopo, avviare il processo di formattazione della riga e chiamare il formattatore di testo FormatLine. Il formattatore di testo recupera i segmenti di testo dall'archivio di testo chiamando il metodo GetTextRun del rispettivo archivio di testo. Gli oggetti TextRun vengono quindi formati in oggetti TextLine dal formattatore di testo e assegnati all'applicazione per l'ispezione o la visualizzazione.
Uso del formattatore di testo
TextFormatter è il motore di formattazione del testo WPF e fornisce servizi per la formattazione e l'interruzione delle righe di testo. Il formattatore di testo può gestire diversi formati di caratteri di testo e stili di paragrafo e include il supporto per il layout di testo internazionale.
A differenza di un'API di testo tradizionale, il TextFormatter interagisce con un client di layout di testo tramite un set di metodi di callback. Richiede al client di fornire questi metodi in un'implementazione della classe TextSource. Il diagramma seguente illustra l'interazione del layout di testo tra l'applicazione client e TextFormatter.
TextFormatter
Il formattatore di testo viene usato per recuperare le righe di testo formattate dall'archivio di testo, che è un'implementazione di TextSource. Questo viene fatto creando prima un'istanza del formattatore di testo utilizzando il metodo Create. Questo metodo crea un'istanza del formattatore di testo e imposta i valori massimi di altezza e larghezza della riga. Non appena viene creata un'istanza del formattatore di testo, il processo di creazione della riga viene avviato chiamando il metodo FormatLine. TextFormatter richiama il testo dalla fonte per recuperare il testo e i parametri di formattazione per le parti di testo che formano una linea.
Nell'esempio seguente viene illustrato il processo di formattazione di un archivio di testo. L'oggetto TextFormatter viene utilizzato per recuperare le righe di testo dall'archivio di testo e quindi formattare la riga di testo per essere disegnata nel 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
Implementazione dell'archivio testo client
Quando si estende il motore di formattazione del testo, è necessario implementare e gestire tutti gli aspetti dell'archivio testo. Questo non è un compito semplice. L'archivio testo è responsabile del rilevamento delle proprietà di esecuzione del testo, delle proprietà di paragrafo, degli oggetti incorporati e di altri contenuti simili. Fornisce inoltre al formattatore di testo singoli oggetti TextRun, che il formattatore di testo utilizza per creare oggetti TextLine.
Per gestire la virtualizzazione dell'archivio di testo, l'archivio di testo deve essere derivato da TextSource. TextSource definisce il metodo utilizzato dal formattatore di testo per recuperare le esecuzioni di testo dall'archivio di testo. GetTextRun è il metodo utilizzato dal formattatore di testo per recuperare i segmenti di testo utilizzati per la formattazione delle righe. La chiamata a GetTextRun viene ripetutamente effettuata dal formattatore di testo fino a quando non si verifica una delle condizioni seguenti:
Viene restituito un TextEndOfLine o una sottoclasse.
La larghezza complessiva dei segmenti di testo supera la larghezza massima della riga specificata nell'invocazione per creare il formattatore di testo o nell'invocazione al metodo FormatLine del formattatore di testo.
Viene restituita una sequenza di nuova linea Unicode, ad esempio "CF", "LF" o "CRLF".
Fornire segmenti di testo
Il nucleo del processo di formattazione del testo è l'interazione tra il formattatore di testo e l'archivio di testo. L'implementazione di TextSource fornisce al formattatore di testo gli oggetti TextRun e le proprietà con cui formattare le esecuzioni di testo. Questa interazione viene gestita dal metodo GetTextRun, chiamato dal formattatore di testo.
La tabella seguente illustra alcuni degli oggetti TextRun predefiniti.
Tipo TextRun | Uso |
---|---|
TextCharacters | Sequenza di testo specializzata utilizzata per passare una rappresentazione di glifi di carattere al formattatore di testo. |
TextEmbeddedObject | Blocco di testo specializzato utilizzato per fornire contenuti in cui la misurazione, l'hit testing e il rendering vengono eseguiti completamente, ad esempio un pulsante o un'immagine all'interno del testo. |
TextEndOfLine | Sequenza di testo specializzata utilizzata per contrassegnare la fine di una riga. |
TextEndOfParagraph | Sequenza di testo specializzata utilizzata per contrassegnare la fine di un paragrafo. |
TextEndOfSegment | Sequenza di testo specializzata utilizzata per contrassegnare la fine di un segmento, ad esempio per terminare l'ambito interessato da un'esecuzione precedente TextModifier. |
TextHidden | Sequenza di testo specializzata utilizzata per contrassegnare un intervallo di caratteri nascosti. |
TextModifier | Esecuzione di testo specializzata utilizzata per modificare le proprietà delle esecuzioni di testo nel relativo ambito. L'ambito si estende alla successiva sequenza di testo corrispondente TextEndOfSegment, o alla successiva TextEndOfParagraph. |
Qualsiasi oggetto TextRun predefinito può essere sottoclassato. Ciò consente alla fonte del testo di fornire al formattatore di testo segmenti di testo che includono dati personalizzati.
Nell'esempio seguente viene illustrato un metodo GetTextRun. Questo archivio di testo restituisce TextRun oggetti al formattatore di testo per l'elaborazione.
// 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
In questo esempio, l'archivio di testo fornisce le stesse proprietà di testo a tutto il testo. Gli archivi di testo avanzati devono implementare la propria gestione dell'intervallo per consentire ai singoli caratteri di avere proprietà diverse.
Specifica delle proprietà di formattazione
TextRun gli oggetti vengono formattati utilizzando le proprietà fornite dall'archivio di testo. Queste proprietà sono disponibili in due tipi, TextParagraphProperties e TextRunProperties. TextParagraphProperties gestire le proprietà inclusive di paragrafo, ad esempio TextAlignment e FlowDirection. TextRunProperties sono proprietà che possono essere diverse per ogni sequenza di testo all'interno di un paragrafo, ad esempio pennello in primo piano, Typefacee dimensioni del carattere. Per l'implementazione di tipi di proprietà di paragrafi personalizzati e frammenti di testo personalizzati, l'applicazione deve creare classi che derivano rispettivamente da TextParagraphProperties e TextRunProperties.
Vedere anche
- Tipografia in WPF
- Documenti in WPF
.NET Desktop feedback