進階文字格式化
Windows Presentation Foundation (WPF) 擁有一套強大的 API,可讓您在應用程式中加入文字。 版面配置和使用者介面 (UI) API,例如 TextBlock,可提供要表現文字時最常見和最常用的元素。 繪圖 API,例如 GlyphRunDrawing 和 FormattedText,可提供在圖畫中加入格式化文字的方法。 在最進階層級,WPF 提供了可延伸的文字格式設定引擎,以控制文字表現的各個層面,例如文字存放區管理、文字執行格式設定管理,以及內嵌物件管理。
本主題為 WPF 文字格式設定簡介。 著重於 WPF 文字格式設定引擎用戶端的實作與使用。
注意
此文件中的所有程式碼範例位於進階文字格式設定範例。
必要條件
本主題以您已對文字表現所需的較高層級 API 使用方式相當熟悉為前提。 大部分使用者情境不會用到本主題討論的進階文字格式設定 API。 如需不同文字 API 的簡介,請參閱 WPF 中的文件。
進階文字格式化
WPF 中的文字版面配置和 UI 控制項提供格式設定屬性,讓您能輕鬆地在應用程式中加入格式化文字。 這些控制項會公開一些屬性來處理文字的呈現方式,包括其字體、大小和色彩。 在一般情況下,這些控制項可以處理您應用程式中大部分的文字呈現。 不過,某些進階的情節需要控制文字儲存以及文字呈現。 WPF 針對這個用途提供可延伸的文字格式設定引擎。
在 WPF 內可找到的進階文字格式設定功能包括文字格式設定引擎、文字存放區、文字執行與格式設定屬性。 文字格式設定引擎 TextFormatter 可建立要表現的文字行。 上述操作是藉由啟用行格式設定流程並呼叫文字格式器 FormatLine 來達成。 文字格式器會呼叫儲存的 GetTextRun 方法,從文字存放區擷取文字執行。 然後文字格式器會將 TextRun 物件變成 TextLine 物件,並呈現給您的應用程式檢查或顯示。
使用文字格式子
TextFormatter 是 WPF 文字格式設定引擎,可提供格式設定和文字分行服務。 文字格式子可處理不同的文字字元格式和段落樣式,且包含國際文字版面配置的支援。
不同於傳統的文字 API,TextFormatter 會透過一組回撥方法與文字版面配置用戶端互動。 它需要用戶端在 TextSource 類別的實作中提供這些方法。 下圖說明用戶端應用程式與 TextFormatter 之間的文字版面配置互動情況。
文字配置用戶端和 TextFormatter 的圖表
文字格式器可從文字存放區擷取格式化的文字行,文字存放區是 TextSource 的實作。 要做到這一點,首先要使用 Create 方法建立文字格式器執行個體。 這個方法會建立文字格式子的執行個體,並設定最大線條高度和寬度的值。 文字格式器執行個體建立後,就會呼叫 FormatLine 方法來啟動行建立流程。 TextFormatter 會回撥文字來源,以擷取形成一行文字執行的文字和格式設定參數。
在下列範例中,會顯示格式設定文字存放區的程序。 TextFormatter 物件可從文字存放區擷取文字行,然後將文字行格式化,繪製進 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
實作用戶端文字存放區
當您延伸文字格式設定引擎時,您必須實作與管理文字存放區的所有層面。 這不是簡單的工作。 文字存放區負責追蹤文字執行屬性、段落屬性、內嵌的物件,以及其他類似的內容。 它亦可提供文字格式器與個別 TextRun 物件,文字格式器會使用這些 TextRun 物件來建立 TextLine 物件。
若要虛擬化文字存放區,文字存放區必須衍生自 TextSource。 TextSource 可定義文字格式器從文字存放區擷取文字執行的方法。 GetTextRun 是文字格式器用來擷取行格式設定使用的文字執行方法。 文字格式器會重複呼叫 GetTextRun,直到出現以下其中一種情況為止:
傳回 TextEndOfLine 或子類別。
文字執行的累積寬度超過建立文字格式器的呼叫或文字格式器的 FormatLine 方法呼叫中指定的最大線條寬度。
傳回 Unicode 新行序列,例如「CF」、「LF」或「CRLF」。
提供文字執行
文字格式設定程序的核心是文字格式子與文字存放區之間的互動。 您的 TextSource 實作會為文字格式器提供 TextRun 物件,以及用於文字執行格式設定的屬性。 上述互動由文字格式器呼叫的 GetTextRun 方法執行。
下表為一些已預先定義的 TextRun 物件。
TextRun 類型 | 使用方式 |
---|---|
TextCharacters | 用來將字元圖像 (glyph) 的表示法傳回文字格式子的特殊文字執行。 |
TextEmbeddedObject | 用來提供內容的特殊文字執行,在這些內容中會整體進行測量、點擊測試和繪製,例如文字內的按鈕或影像。 |
TextEndOfLine | 用來標記行尾的特殊文字執行。 |
TextEndOfParagraph | 用來標記段落結尾的特殊文字執行。 |
TextEndOfSegment | 用來標記區段結尾的特殊文字執行,例如受到前一個 TextModifier 執行影響的範圍結尾。 |
TextHidden | 用來標記隱藏字元範圍的特殊文字執行。 |
TextModifier | 用來在文字執行範圍中修改其屬性的特殊文字執行。 範圍會延伸至下一個相符的文字執行 TextEndOfSegment,或下一個 TextEndOfParagraph。 |
所有已預先定義的 TextRun 物件都可以被子類別化。 這可讓文字來源提供文字格式子包含自訂資料的文字執行。
以下範例將說明 GetTextRun 方法。 此文字存放區會將 TextRun 物件傳回給文字格式器進行處理。
// 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
注意
在此範例中,文字存放區提供相同的文字屬性給所有文字。 進階的文字存放區必須實作自己的範圍管理,以允許個別字元可以有不同的屬性。
指定格式設定屬性
TextRun 物件是透過文字存放區提供的屬性進行格式化。 這些屬性共有兩種類型,TextParagraphProperties 和 TextRunProperties。 TextParagraphProperties 可處理段落內含屬性,例如 TextAlignment 和 FlowDirection。 TextRunProperties 可為段落內每個文字運行不同的屬性,例如幕前筆刷、Typeface 和字型大小。 若要實作自訂段落和自訂文字執行屬性類型,您的應用程式必須分別建立衍生自 TextParagraphProperties 和 TextRunProperties 的類別。