Formattazione del testo avanzata

Windows Presentation Foundation (WPF) fornisce un set di APIs molto efficace per includere testo nell'applicazione. Il layout e le APIs  dell'user interface (UI), ad esempio TextBlock, forniscono gli elementi di utilizzo più comune e generale per la presentazione del testo. Le APIs di disegno, quali GlyphRunDrawing e FormattedText, consentono di includere il testo formattato nei disegni. Al livello più avanzato, WPF fornisce un motore di formattazione del testo estensibile per controllare qualsiasi aspetto della presentazione del testo, ad esempio la gestione degli archivi di testo, la gestione della formattazione di sequenze di testo e la gestione degli oggetti incorporati.

In questo argomento viene presentata un'introduzione alla formattazione del testo in WPF. Vengono descritti in particolare l'implementazione del client e l'utilizzo del motore di formattazione del testo di WPF.

NotaNota

Tutti gli esempi di codice all'interno di questo documento sono disponibili in Esempio di formattazione di testo avanzata.

Nel presente argomento sono contenute le seguenti sezioni.

  • Prerequisiti
  • Formattazione del testo avanzata
  • Utilizzo del formattatore di testo
  • Implementazione dell'archivio di testo del client
  • Inserimento delle sequenze di testo
  • Specifica delle proprietà di formattazione
  • Argomenti correlati

Prerequisiti

Questo argomento presuppone che l'utente abbia dimestichezza con le APIs di livello più elevato utilizzate per la presentazione del testo. La maggior parte degli scenari utente non richiede l'utilizzo delle APIs di formattazione del testo avanzata illustrate in questo argomento. Per un'introduzione alle diverse APIs di testo, vedere Documenti in WPF.

Formattazione del testo avanzata

Il layout del testo e i controlli dell'UI di WPF offrono proprietà di formattazione che consentono di includere facilmente un 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 situazioni ordinarie, 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. A tal fine, in WPF viene fornito un motore di formattazione del testo estensibile.

Le funzionalità di formattazione del testo avanzata di WPF sono costituite da un motore di formattazione del testo, da un archivio di testo, da sequenze di testo e da proprietà di formattazione. Il motore di formattazione del testo, TextFormatter, crea righe di testo da utilizzare per la presentazione. Per effettuare questa operazione, è necessario avviare il processo di formattazione delle righe e chiamare l'oggetto FormatLine del formattatore di testo. Il formattatore di testo recupera le sequenze di testo dall'archivio di testo chiamando il metodo GetTextRun dell'archivio. Gli oggetti TextRun vengono quindi trasformati in oggetti TextLine dal formattatore di testo e passati all'applicazione per l'ispezione o la visualizzazione.

Utilizzo del formattatore di testo

TextFormatter è il motore di formattazione del testo di WPF e fornisce servizi per la formattazione delle righe di testo e per l'inserimento di interruzioni di riga. 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, l'oggetto TextFormatter interagisce con un client di layout di testo tramite un insieme di metodi di callback. È necessario che il client fornisca questi metodi in un'implementazione della classe TextSource. Nel seguente diagramma viene illustrata l'interazione di layout di testo tra l'applicazione client e TextFormatter.

Interazione tra l'applicazione e TextFormatter

Diagramma del client del layout di testo e TextFormatter

Il formattatore di testo viene utilizzato per recuperare le righe del testo formattato dall'archivio di testo, che costituisce un'implementazione di TextSource. Questa operazione viene eseguita creando innanzitutto un'istanza del formattatore di testo tramite il metodo Create. Questo metodo crea un'istanza del formattatore di testo e imposta i valori massimi di altezza e larghezza della riga. Una volta creata un'istanza del formattatore di testo, viene avviato il processo di creazione della riga tramite la chiamata al metodo FormatLine. L'oggetto TextFormatter richiama l'origine del testo per recuperare il testo e i parametri di formattazione per le sequenze di testo che formano una riga.

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 formattare quindi la riga di testo per il disegno nell'oggetto DrawingContext.

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

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 oggetti TextRun che il formattatore utilizza per creare oggetti TextLine.

Per gestire la virtualizzazione dell'archivio di testo, quest'ultimo deve essere derivato da TextSource. TextSource definisce il metodo utilizzato dal formattatore di testo per recuperare le sequenze di testo dall'archivio di testo. GetTextRun è il metodo che consente di recuperare le sequenze di testo utilizzate nella formattazione delle righe. La chiamata a GetTextRun viene effettuata ripetutamente dal formattatore di testo finché non si verifica una delle seguenti condizioni:

  • Viene restituito un oggetto TextEndOfLine o una sottoclasse.

  • La larghezza complessiva delle sequenze di testo supera la larghezza massima della riga specificata nella chiamata per creare il formattatore di testo o nella chiamata al metodo FormatLine del formattatore di 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 è dato dall'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 sequenze di testo. Questa interazione viene gestita dal metodo GetTextRun, chiamato dal formattatore di testo.

Nella tabella seguente sono riportati alcuni degli oggetti TextRun predefiniti.

Tipo TextRun

Utilizzo

TextCharacters

Sequenza di testo specializzata utilizzata per passare nuovamente al formattatore di testo una rappresentazione dei glifi dei caratteri.

TextEmbeddedObject

Sequenza di testo specializzata utilizzata per fornire un 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 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 di TextModifier.

TextHidden

Sequenza di testo specializzata utilizzata per contrassegnare un intervallo di caratteri nascosti.

TextModifier

Sequenza di testo specializzata utilizzata per modificare le proprietà delle sequenze di testo nel relativo ambito. L'ambito si estende alla successiva sequenza di testo TextEndOfSegment corrispondente o al successivo oggetto TextEndOfParagraph.

Qualsiasi oggetto TextRun predefinito 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 metodo GetTextRun. Questo archivio di testo restituisce oggetti TextRun al formattatore di testo per l'elaborazione.

      ' 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
// 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);
}
NotaNota

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 disporre di più proprietà.

Specifica delle proprietà di formattazione

Gli oggetti TextRun vengono formattati utilizzando le proprietà fornite dall'archivio di testo. Queste proprietà possono essere di due tipi, TextParagraphProperties e TextRunProperties. TextParagraphProperties gestisce le proprietà che interessano il paragrafo, quali TextAlignment e FlowDirection. TextRunProperties include proprietà che possono essere diverse per ciascuna sequenza di testo all'interno di un paragrafo, ad esempio il pennello per il primo piano, Typeface e le dimensioni del carattere. Per implementare i tipi di proprietà dei paragrafi e delle sequenze di testo personalizzati, l'applicazione deve creare delle classi che derivano rispettivamente da TextParagraphProperties e da TextRunProperties.

Vedere anche

Concetti

Funzionalità tipografiche di WPF

Documenti in WPF