Freigeben über


Erweiterte Textformatierung

Windows Presentation Foundation (WPF) bietet einen robusten Satz von APIs zum Einschließen von Text in Ihrer Anwendung. Layout- und Benutzeroberflächen-APIs, z. B. TextBlock, stellen die am häufigsten verwendeten und allgemein verwendeten Elemente für die Textpräsentation bereit. Zeichnungs-APIs wie GlyphRunDrawing und FormattedTextbieten ein Mittel zum Einschließen von formatiertem Text in Zeichnungen. Auf der fortschrittlichsten Ebene bietet WPF ein erweiterbares Textformatierungsmodul, um jeden Aspekt der Textpräsentation zu steuern, z. B. Textspeicherverwaltung, Formatierungsverwaltung für Textlauf und eingebettete Objektverwaltung.

Dieses Thema enthält eine Einführung in die WPF-Textformatierung. Der Schwerpunkt liegt auf der Clientimplementierung und Verwendung des WPF-Textformatierungsmoduls.

Anmerkung

Alle Codebeispiele in diesem Dokument finden Sie im Beispiel für erweiterte Textformatierung.

Voraussetzungen

In diesem Thema wird davon ausgegangen, dass Sie mit den APIs der höheren Ebene vertraut sind, die für die Textpräsentation verwendet werden. Die meisten Benutzerszenarien erfordern nicht die erweiterten Textformatierungs-APIs, die in diesem Thema besprochen werden. Eine Einführung in die verschiedenen Text-APIs finden Sie unter Dokumente in WPF.

Erweiterte Textformatierung

Das Textlayout und die UI-Steuerelemente in WPF stellen Formatierungseigenschaften bereit, mit denen Sie formatierten Text ganz einfach in Ihre Anwendung aufnehmen können. Diese Steuerelemente stellen eine Reihe von Eigenschaften zur Verfügung, um die Darstellung von Texten zu handhaben, einschließlich Schriftart, Größe und Farbe. Unter normalen Umständen können diese Steuerelemente den Großteil der Textpräsentation in Ihrer Anwendung verarbeiten. Einige erweiterte Szenarien erfordern jedoch die Steuerung des Textspeichers sowie die Textpräsentation. WPF stellt hierfür ein erweiterbares Textformatierungsmodul bereit.

Die erweiterten Textformatierungsfeatures in WPF bestehen aus einem Textformatierungsmodul, einem Textspeicher, Textläufen und Formatierungseigenschaften. Das Textformatierungsmodul TextFormattererstellt Textzeilen, die für die Präsentation verwendet werden sollen. Dies wird erreicht, indem der Zeilenformatierungsprozess eingeleitet und die FormatLine des Textformatierungsprogramms aufgerufen wird. Das Textformatierungsprogramm ruft Lauftexte aus Ihrem Textspeicher ab, indem er die GetTextRun-Methode des Speichers aufruft. Die TextRun Objekte werden dann durch den Textformatierer in TextLine Objekte gebildet und der Anwendung zur Inspektion oder Anzeige zur Verfügung gestellt.

Verwendung des Textformatierers

TextFormatter ist das WPF-Textformatierungsmodul und bietet Dienste zum Formatieren und Unterbrechen von Textzeilen. Der Textformatierer kann unterschiedliche Textzeichenformate und Absatzformatvorlagen verarbeiten und enthält Unterstützung für internationales Textlayout.

Im Gegensatz zu einer traditionellen Text-API interagiert der TextFormatter über eine Reihe von Rückrufmethoden mit einem Textlayout-Client. Es erfordert, dass der Client diese Methoden in einer Implementierung der Klasse TextSource bereitstellt. Das folgende Diagramm veranschaulicht die Textlayoutinteraktion zwischen der Clientanwendung und TextFormatter.

Diagramm des Textlayout-Clients und TextFormatter

Das Textformatierungsprogramm wird verwendet, um formatierte Textzeilen aus dem Textspeicher abzurufen, was eine Implementierung von TextSource ist. Dazu erstellen Sie zunächst eine Instanz des Textformatierers mithilfe der Create-Methode. Diese Methode erstellt eine Instanz des Textformatierers und legt die maximalen Zeilenhöhen- und Breitenwerte fest. Sobald eine Instanz des Textformatierers erstellt wird, wird der Zeilenerstellungsprozess gestartet, indem die FormatLine-Methode aufgerufen wird. TextFormatter führt Rückrufe an die Textquelle durch, um die Text- und Formatierungsparameter für die Textausführungen abzurufen, die eine Zeile bilden.

Im folgenden Beispiel wird der Prozess zum Formatieren eines Textspeichers angezeigt. Das TextFormatter-Objekt wird verwendet, um Textzeilen aus dem Textspeicher abzurufen und dann die Textzeile zum Zeichnen in DrawingContext zu formatieren.

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

Implementieren des Clienttextspeichers

Wenn Sie das Textformatierungsmodul erweitern, müssen Sie alle Aspekte des Textspeichers implementieren und verwalten. Dies ist keine triviale Aufgabe. Der Textspeicher ist für das Nachverfolgen von Textlaufeigenschaften, Absatzeigenschaften, eingebetteten Objekten und anderen ähnlichen Inhalten verantwortlich. Außerdem werden dem Textformatierungsprogramm einzelne TextRun-Objekte zur Verfügung gestellt, aus denen das Textformatierungsprogramm TextLine-Objekte erstellt.

Um die Virtualisierung des Textspeichers zu verarbeiten, muss der Textspeicher von TextSourceabgeleitet werden. TextSource definiert die Methode, die der Textformatierer zum Abrufen von Textläufen aus dem Textspeicher verwendet. GetTextRun ist die vom Textformatierungsprogramm verwendete Methode zum Abrufen von Lauftexten für die Zeilenformatierung. Der Aufruf von GetTextRun wird vom Textformatierungsprogramm so lange wiederholt, bis eine der folgenden Bedingungen eintritt:

  • Ein TextEndOfLine oder eine Unterklasse wird zurückgegeben.

  • Die kumulierte Breite des Lauftexts überschreitet die maximale Zeilenbreite, die entweder im Aufruf zum Erstellen des Textformatierungsprogramms oder im Aufruf der FormatLine-Methode des Textformatierungsprogramms angegeben ist.

  • Eine Unicode-Zeilenvorschubsequenz, z. B. „CF“, „LF“ oder „CRLF“ wird zurückgegeben.

Bereitstellen von Lauftexten

Der Kern des Textformatierungsprozesses ist die Interaktion zwischen dem Textformatierer und dem Textspeicher. Ihre Implementierung von TextSource liefert dem Textformatierungsprogramm die TextRun-Objekte und die Eigenschaften, mit denen die Lauftexte formatiert werden. Diese Interaktion wird von der GetTextRun-Methode behandelt, die vom Textformatierer aufgerufen wird.

Die folgende Tabelle enthält einige der vordefinierten TextRun-Objekte.

TextRun-Typ Verwendung
TextCharacters Der spezialisierte Lauftext, der zum Übergeben einer Darstellung von Zeichensymbolen zurück an den Textformatierer verwendet wird
TextEmbeddedObject Der spezialisierte Lauftext, der zum Bereitstellen von Inhalt verwendet wird, in dem Messungen, Treffertests und Zeichnungen komplett ausgeführt werden, z. B. eine Schaltfläche oder ein Bild im Text
TextEndOfLine Der spezielle Textlauf, der zum Markieren des Endes einer Zeile verwendet wird.
TextEndOfParagraph Der spezielle Textlauf, der zum Markieren des Endes eines Absatzes verwendet wird.
TextEndOfSegment Der spezialisierte Lauftext, der zum Kennzeichnen des Segmentendes verwendet wird, z. B. um den Bereich zu beenden, der von einer vorherigen TextModifier-Ausführung betroffen ist.
TextHidden Der spezialisierte Lauftext, der verwendet wird, um eine Reihe ausgeblendeter Zeichen zu kennzeichnen
TextModifier Der spezialisierte Lauftext, der verwendet wird, um Eigenschaften der Lauftexte in deren Bereich zu ändern. Der Bereich erstreckt sich bis zum nächsten übereinstimmenden TextEndOfSegment-Lauftext bzw. bis zum nächsten TextEndOfParagraph.

Jedes der vordefinierten TextRun-Objekte kann unterklassigt werden. Auf diese Weise kann Ihre Textquelle den Textformatierer mit Textläufen bereitstellen, die benutzerdefinierte Daten enthalten.

Das folgende Beispiel veranschaulicht eine GetTextRun-Methode. Dieser Textspeicher gibt TextRun-Objekte für die Verarbeitung an das Textformatierungsprogramm zurück.

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

Anmerkung

In diesem Beispiel stellt der Textspeicher die gleichen Texteigenschaften für den gesamten Text bereit. Erweiterte Textspeicher müssen ihre eigene Verwaltung für Bereiche implementieren, damit einzelne Zeichen über unterschiedliche Eigenschaften verfügen können.

Angeben von Formatierungseigenschaften

TextRun Objekte werden mithilfe von Eigenschaften formatiert, die vom Textspeicher bereitgestellt werden. Diese Eigenschaften kommen in zwei Typen, TextParagraphProperties und TextRunProperties. TextParagraphProperties handhaben Eigenschaften, die den Absatz umfassen, wie TextAlignment und FlowDirection. TextRunProperties sind Eigenschaften, die für jeden Lauftext innerhalb eines Absatzes unterschiedlich sein können, z. B. Vordergrundpinsel, Typeface und Schriftgröße. Um benutzerdefinierte Absatz- und Lauftext-Eigenschaftstypen zu implementieren, muss Ihre Anwendung Klassen erstellen, die von TextParagraphProperties bzw. TextRunProperties abgeleitet sind.

Weitere Informationen