Erweiterte Textformatierung

Windows Presentation Foundation (WPF) stellt einen stabilen Satz von APIs bereit, um Text in Ihre Anwendung einzuschließen. 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 z. B. GlyphRunDrawing und FormattedText, bieten die Möglichkeit, formatierten Text in Zeichnungen aufzunehmen. Auf der höchsten Ebene bietet WPF eine erweiterbare Engine zur Textformatierung, um jeden Aspekt der Textdarstellung zu steuern, z. B. die Speicherverwaltung für Text, die Formatierungsverwaltung des Lauftexts und die Verwaltung eingebetteter Objekte.

Dieses Thema enthält eine Einführung in die WPF-Textformatierung. Der Schwerpunkt liegt auf der Client-Implementierung und der Verwendung der WPF-Textformatierungs-Engine.

Hinweis

Alle Codebeispiele in diesem Dokument finden Sie im Advanced Text Formatting Sample (Beispiel zur erweiterten Testformatierung).

Voraussetzungen

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

Erweiterte Textformatierung

Das Textlayout und Benutzeroberflächen-Steuerelemente in WPF stellen Formatierungseigenschaften bereit, mit denen Sie einfach formatierten Text in Ihre Anwendung einfügen können. Diese Steuerelemente bieten eine Reihe von Eigenschaften, um die Darstellung von Text zu bearbeiten, u.a. dessen Schriftart, Größe und Farbe. Unter normalen Umständen können diese Steuerelemente den Großteil der Textdarstellung in Ihrer Anwendung behandeln. Einige erweiterten Szenarios erfordern jedoch das Steuerelement des Textspeichers sowie die Textdarstellung. WPF stellt eine erweiterbare Textformatierungs-Engine für diesen Zweck bereit.

Die erweiterten Funktionen zur Textformatierung, die in WPF zu finden sind, bestehen aus einer Textformatierungs-Engine, einem Textspeicher, aus Lauftexten und Formatierungseigenschaften. Die Textformatierungs-Engine, TextFormatter, erstellt Textzeilen für die Verwendung in der Präsentation. Dies wird erreicht, indem der Zeilenformatierungsprozess eingeleitet und die FormatLine des Textformatierungsprogramms aufgerufen wird. DasTextformatierungsprogramm ruft Lauftexte aus Ihrem Textspeicher ab, indem er die GetTextRun-Methode des Speichers aufruft. Die TextRun-Objekte werden dann vom Textformatierungsprogramm in TextLine-Objekte umgewandelt und an Ihre Anwendung zur Prüfung oder Anzeige übergeben.

Verwendung des Textformatierers

TextFormatter ist die WPF-Textformatierungs-Engine und bietet Dienste zur Formatierung und zum Umbrechen 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.

Diagram of text layout client and TextFormatter

Das Textformatierungsprogramm wird verwendet, um formatierte Textzeilen aus dem Textspeicher abzurufen, was eine Implementierung von TextSource ist. Dazu wird zunächst mit der Create-Methode eine Instanz des Textformatierungsprogramms erstellt. Diese Methode erstellt eine Instanz des Textformatierungsprogramms und legt die maximalen Werte für Zeilenhöhe und -breite fest. Sobald eine Instanz des Textformatierungsprogramms erstellt ist, wird der Prozess der Zeilenerstellung durch den Aufruf der FormatLine-Methode gestartet. TextFormatter führt Rückrufe an die Textquelle durch, um die Text- und Formatierungsparameter für den Lauftext abzurufen, die eine Zeile bilden.

Im folgenden Beispiel wird der Formatierungsprozess eines Textspeichers gezeigt. Das TextFormatter-Objekt wird verwendet, um Textzeilen aus dem Textspeicher abzurufen und dann die Textzeile zum Zeichnen in den 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 die Textformatierungs-Engine erweitern, müssen Sie alle Aspekte des Textspeichers implementieren und verwalten. Dies ist keine einfache Aufgabe. Der Textspeicher ist für die Nachverfolgung von Lauftexteigenschaften, Absatzeigenschaften, für das Einbetten von Objekten und anderen ähnlichen Inhalt verantwortlich. Außerdem werden dem Textformatierungsprogramm einzelne TextRun-Objekte zur Verfügung gestellt, aus denen das Textformatierungsprogramm TextLine-Objekte erstellt.

Um die Virtualisierung von Textspeicher handhaben zu können, muss der Textspeicher von TextSource abgeleitet werden. TextSource definiert die Methode, die das Textformatierungsprogramm benutzt, um Lauftext aus dem Textspeicher abzurufen. GetTextRun ist die vom Textformatierungsprogramm verwendete Methode zum Abrufen von Lauftext 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 Lauftext

Der wichtigste Teil des Textformatierunsprozesses ist die Interaktion zwischen Textformatierer und 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 gehandhabt, die vom Textformatierungsprogramm aufgerufen wird.

In der folgenden Tabelle werden einige der vordefinierten TextRun-Objekte aufgeführt.

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 spezialisierte Lauftext, der zum Kennzeichnen des Zeilenendes verwendet wird
TextEndOfParagraph Der spezialisierte Lauftext, der zum Kennzeichnen eines Absatzendes 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 in Unterklassen unterteilt werden. Dadurch kann Ihre Textquelle den Textformatierer mit Lauftexten 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

Hinweis

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 der vom Textspeicher bereitgestellten Eigenschaften formatiert. Diese Eigenschaften kommen in zwei Typen, TextParagraphProperties und TextRunProperties. TextParagraphProperties handhaben Absatz-inklusive Eigenschaften 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.

Siehe auch