Condividi tramite


Formattazione del testo avanzata

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 di testo avanzata.

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 del testo avanzata

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 numerose proprietà per la gestione della presentazione del testo, inclusi il carattere tipografico, le dimensioni e il colore. In circostanze normali, questi controlli sono in grado di gestire la maggior parte degli scenari di presentazione del 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. Ciò si ottiene avviando il processo di formattazione della riga e chiamando il formattatore di FormatLinetesto . Il formattatore di testo recupera le esecuzioni di testo dall'archivio di testo chiamando il metodo dell'archivio GetTextRun . Gli TextRun oggetti vengono quindi formati in TextLine oggetti 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 di righe di testo. Il formattatore di testo può gestire diversi formati di carattere del testo e stili di paragrafo e include il supporto per il layout di testo internazionale.

A differenza di un'API di testo tradizionale, interagisce TextFormatter 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 TextSource classe . Il diagramma seguente illustra l'interazione del layout di testo tra l'applicazione client e TextFormatter.

Diagram of text layout client and TextFormatter

Il formattatore di testo viene usato per recuperare righe di testo formattate dall'archivio di testo, ovvero un'implementazione di TextSource. A tale scopo, creare prima un'istanza del formattatore di testo usando il Create metodo . 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 FormatLine metodo . TextFormatter richiama all'origine testo per recuperare il testo e i parametri di formattazione per le esecuzioni di testo che formano una riga.

L'esempio seguente illustra 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 linea di testo per il disegno in 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 di testo del client

Quando si estende il motore di formattazione del testo, è necessario implementare e gestire tutti gli aspetti dell'archivio di testo. Non si tratta di un'attività elementare. L'archivio di testo è responsabile del rilevamento delle proprietà delle sequenze di testo, delle proprietà dei paragrafi, degli oggetti incorporati e di altri contenuti simili. Fornisce inoltre al formattatore di testo singoli TextRun oggetti utilizzati dal formattatore di testo per creare TextLine oggetti.

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 le esecuzioni di testo utilizzate nella formattazione della riga. La chiamata a GetTextRun viene ripetutamente effettuata dal formattatore di testo fino a quando non si verifica una delle condizioni seguenti:

  • Viene TextEndOfLine restituita una sottoclasse o .

  • La larghezza accumulata delle esecuzioni di testo supera la larghezza massima della riga specificata nella chiamata per creare il formattatore di testo o la chiamata al metodo del formattatore di FormatLine testo.

  • Viene restituita una sequenza di nuova riga Unicode, ad esempio "CF", "LF" o "CRLF".

Inserimento delle sequenze di testo

Il fulcro del processo di formattazione del testo è rappresentato dall'interazione tra il formattatore di testo e l'archivio di testo. L'implementazione di fornisce al formattatore di TextSource testo gli TextRun oggetti e le proprietà con cui formattare le esecuzioni di testo. Questa interazione viene gestita dal GetTextRun metodo , chiamato dal formattatore di testo.

Nella tabella seguente vengono illustrati alcuni degli oggetti predefiniti TextRun .

Tipo di TextRun Utilizzo
TextCharacters Sequenza di testo specializzata usata per passare nuovamente al formattatore di testo una rappresentazione dei glifi dei caratteri.
TextEmbeddedObject Sequenza di testo specializzata usata per fornire contenuto nel quale la misurazione, l'hit testing e il disegno vengono eseguite come un'unica operazione, ad esempio un pulsante o un'immagine all'interno del testo.
TextEndOfLine Sequenza di testo specializzata usata per contrassegnare la fine di una riga.
TextEndOfParagraph Sequenza di testo specializzata usata 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 usata per contrassegnare un intervallo di caratteri nascosti.
TextModifier Sequenza di testo specializzata usata per modificare le proprietà delle sequenze di testo nel relativo ambito. L'ambito si estende alla successiva esecuzione del testo corrispondente TextEndOfSegment o alla successiva TextEndOfParagraph.

Qualsiasi oggetto predefinito TextRun può essere sottoclassato. Ciò consente all'origine del testo di fornire al formattatore di testo sequenze di testo che includono dati personalizzati.

Nell'esempio seguente viene illustrato un GetTextRun metodo . 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 a tutto il testo le stesse proprietà. Gli archivi di testo avanzati devono implementare una gestione personalizzata dell'estensione in modo da 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 e TextParagraphPropertiesTextRunProperties. TextParagraphProperties gestire le proprietà inclusive del paragrafo, TextAlignment ad esempio e FlowDirection. TextRunProperties sono proprietà che possono essere diverse per ogni sequenza di testo all'interno di un paragrafo, ad esempio il pennello in primo piano, Typefacee le dimensioni del carattere. Per implementare tipi di proprietà di esecuzione di testo personalizzati e paragrafi personalizzati, l'applicazione deve creare classi che derivano rispettivamente da TextParagraphProperties e TextRunProperties .

Vedi anche