WPF 支援透過使用功能豐富的使用者介面 (UI) 控制項來呈現文字內容。 一般而言,您可以將文字轉譯劃分為三個層級:
使用 FormattedText 物件。
使用高階控制項,例如 TextBlock 和 FlowDocument 物件。
本主題提供文字轉譯的效能建議。
在圖像層級轉譯文字
Windows Presentation Foundation (WPF) 提供進階的文字支援 (包括字符層級標記),可為想要在格式化之後攔截和保存文字的客戶直接存取 Glyphs。 這些功能可針對下列每個案例中的不同文字轉譯需求提供重要支援。
固定格式文件的螢幕顯示。
列印案例。
使用 Extensible Application Markup Language (XAML) 作為裝置印表機語言。
Microsoft XPS Document Writer。
先前的印表機驅動程式,從 Win32 應用程式輸出為固定格式。
列印多工緩衝處理格式。
固定格式文件呈現,包括舊版 Windows 和其他運算裝置的用戶端。
備註
Glyphs 和 GlyphRun 是專為固定格式的文件呈現和列印案例而設計。 WPF 針對一般配置和使用者介面 (UI) 案例提供數個元素,例如 Label 和 TextBlock。 如需版面配置和 UI 案例的詳細資訊,請參閱 WPF 中的印刷樣式。
下列範例說明如何在 XAML 中定義 Glyphs 物件的屬性。 此範例假設 Arial、Courier New 和 Times New Roman 字型會安裝在本機電腦的 C:\WINDOWS\Fonts 資料夾。
<!-- The example shows how to use a Glyphs object. -->
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
>
<StackPanel Background="PowderBlue">
<Glyphs
FontUri = "C:\WINDOWS\Fonts\TIMES.TTF"
FontRenderingEmSize = "100"
StyleSimulations = "BoldSimulation"
UnicodeString = "Hello World!"
Fill = "Black"
OriginX = "100"
OriginY = "200"
/>
</StackPanel>
</Page>
使用 DrawGlyphRun
如果您有自訂控制項,且想要轉譯圖像,請使用 DrawGlyphRun 方法。
WPF 也會透過使用 FormattedText 物件,提供自訂文字格式設定的較低層級服務。 在 Windows Presentation Foundation (WPF) 中轉譯文字最有效率的方式是使用 Glyphs 和 GlyphRun 在圖像層級產生文字內容。 不過,此效率的代價是遺失容易使用的 RTF 格式設定,這是 Windows Presentation Foundation (WPF) 控制項的內建功能,例如 TextBlock 和 FlowDocument。
FormattedText 物件
FormattedText 物件可讓您繪製多行文字,其中文字中的每個字元都可以個別格式化。 如需詳細資訊,請參閱繪製格式化的文字。
若要建立格式化的文字,請呼叫 FormattedText 建構函式來建立 FormattedText 物件。 建立初次格式化的文字字串之後,您就可以套用一系列的格式化樣式。 如果您的應用程式想要實作自己的版面配置,則 FormattedText 物件比使用控制項更好,例如 TextBlock。 如需更多有關 FormattedText 物件的資訊,請參閱繪製格式化文字。
FormattedText 物件提供低階文字格式設定功能。 您可以將多個格式化樣式套用到一或多個字元。 例如,您可以呼叫 SetFontSize 和 SetForegroundBrush 方法來變更文字中前五個字元的格式。
下列程式碼範例會建立 FormattedText 物件並轉譯物件。
protected override void OnRender(DrawingContext drawingContext)
{
string testString = "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor";
// Create the initial formatted text string.
FormattedText formattedText = new FormattedText(
testString,
CultureInfo.GetCultureInfo("en-us"),
FlowDirection.LeftToRight,
new Typeface("Verdana"),
32,
Brushes.Black);
// Set a maximum width and height. If the text overflows these values, an ellipsis "..." appears.
formattedText.MaxTextWidth = 300;
formattedText.MaxTextHeight = 240;
// Use a larger font size beginning at the first (zero-based) character and continuing for 5 characters.
// The font size is calculated in terms of points -- not as device-independent pixels.
formattedText.SetFontSize(36 * (96.0 / 72.0), 0, 5);
// Use a Bold font weight beginning at the 6th character and continuing for 11 characters.
formattedText.SetFontWeight(FontWeights.Bold, 6, 11);
// Use a linear gradient brush beginning at the 6th character and continuing for 11 characters.
formattedText.SetForegroundBrush(
new LinearGradientBrush(
Colors.Orange,
Colors.Teal,
90.0),
6, 11);
// Use an Italic font style beginning at the 28th character and continuing for 28 characters.
formattedText.SetFontStyle(FontStyles.Italic, 28, 28);
// Draw the formatted text string to the DrawingContext of the control.
drawingContext.DrawText(formattedText, new Point(10, 0));
}
Protected Overrides Sub OnRender(ByVal drawingContext As DrawingContext)
Dim testString As String = "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor"
' Create the initial formatted text string.
Dim formattedText As New FormattedText(testString, CultureInfo.GetCultureInfo("en-us"), FlowDirection.LeftToRight, New Typeface("Verdana"), 32, Brushes.Black)
' Set a maximum width and height. If the text overflows these values, an ellipsis "..." appears.
formattedText.MaxTextWidth = 300
formattedText.MaxTextHeight = 240
' Use a larger font size beginning at the first (zero-based) character and continuing for 5 characters.
' The font size is calculated in terms of points -- not as device-independent pixels.
formattedText.SetFontSize(36 * (96.0 / 72.0), 0, 5)
' Use a Bold font weight beginning at the 6th character and continuing for 11 characters.
formattedText.SetFontWeight(FontWeights.Bold, 6, 11)
' Use a linear gradient brush beginning at the 6th character and continuing for 11 characters.
formattedText.SetForegroundBrush(New LinearGradientBrush(Colors.Orange, Colors.Teal, 90.0), 6, 11)
' Use an Italic font style beginning at the 28th character and continuing for 28 characters.
formattedText.SetFontStyle(FontStyles.Italic, 28, 28)
' Draw the formatted text string to the DrawingContext of the control.
drawingContext.DrawText(formattedText, New Point(10, 0))
End Sub
FlowDocument、TextBlock 和 Label 控制項
WPF 包含多個控制項,可用來將文字繪製到畫面。 每個控制項都是不同案例的目標,且有自己的功能與限制清單。
FlowDocument 對效能的影響超過 TextBlock 或 Label
一般而言,需要有限的文字支援時,應該使用 TextBlock 元素,例如使用者介面 (UI) 中的簡短句子。 當需要最少的文字支援時,可以使用Label。 FlowDocument 元素是可自動重排文件的容器,可支援豐富的內容呈現,因此,其效能影響大於使用 TextBlock 或 Label 控制項。
如需關於 FlowDocument 的詳細資訊,請參閱非固定格式文件概觀。
避免在 FlowDocument 中使用 TextBlock
TextBlock 元素衍生自 UIElement。 Run 元素衍生自 TextElement,其使用成本比 UIElement 衍生的物件低。 可能的話,請使用 Run (而不是 TextBlock) 在 FlowDocument 中顯示文字內容。
下列標記範例說明在 FlowDocument 中設定文字內容的兩種方式:
<FlowDocument>
<!-- Text content within a Run (more efficient). -->
<Paragraph>
<Run>Line one</Run>
</Paragraph>
<!-- Text content within a TextBlock (less efficient). -->
<Paragraph>
<TextBlock>Line two</TextBlock>
</Paragraph>
</FlowDocument>
避免使用 Run 來設定文字屬性
一般而言,在 TextBlock 中使用 Run 會比完全不使用明確 Run 物件更耗用效能。 如果您使用 Run 來設定文字屬性,請改為直接在 TextBlock 上設定這些屬性。
下列標記範例說明設定文字屬性的兩種方式,在此案例中,FontWeight 屬性:
<!-- Run is used to set text properties. -->
<TextBlock>
<Run FontWeight="Bold">Hello, world</Run>
</TextBlock>
<!-- TextBlock is used to set text properties, which is more efficient. -->
<TextBlock FontWeight="Bold">
Hello, world
</TextBlock>
下表顯示 1000 個有無明確 Run 之 TextBlock 物件的成本。
TextBlock 類型 | 建立時間 (毫秒) | 轉譯時間 (毫秒) |
---|---|---|
Run 設定文字屬性 | 146 | 540 |
TextBlock 設定文字屬性 | 43 | 453 |
避免資料繫結至 Label.Content 屬性
假設您有頻繁地從 String 來源更新之 Label 物件的案例。 當資料將 Label 元素的 Content 屬性繫結至 String 來源物件時,您可能會遇到效能不佳。 每次更新來源 String 時,系統都會捨棄舊 String 物件並重新建立新的 String,因為 String 物件是不可變的,所以無法修改。 這又會導致 Label 物件的 ContentPresenter 捨棄其舊內容,並重新產生新內容以顯示新的 String。
這個問題的解決方法很簡單。 如果 Label 未設定為自訂 ContentTemplate 值,請將 Label 取代為 TextBlock,並將其 Text 屬性繫結至來源字串。
資料繫結屬性 | 更新時間 (毫秒) |
---|---|
標籤.內容 | 835 |
TextBlock.Text | 242 |
超連結
Hyperlink 物件是一種內嵌層級非固定格式內容項目,可讓您將超連結置於非固定格式內容內。
在一個 TextBlock 物件中合併超連結
您可以將多個 Hyperlink 元素分組在相同的 TextBlock 內,以最佳化多個元素的使用。 這可讓您在應用程式中建立的物件數目降到最低。 例如,您可能想要顯示多個超連結,如下所示:
MSN 首頁 | 我的 MSN
下列標記範例顯示用來顯示超連結的多個 TextBlock 元素:
<!-- Hyperlinks in separate TextBlocks. -->
<TextBlock>
<Hyperlink TextDecorations="None" NavigateUri="http://www.msn.com">MSN Home</Hyperlink>
</TextBlock>
<TextBlock Text=" | "/>
<TextBlock>
<Hyperlink TextDecorations="None" NavigateUri="http://my.msn.com">My MSN</Hyperlink>
</TextBlock>
下列標記範例示範更有效率的超連結顯示方式,這次將使用單一 TextBlock:
<!-- Hyperlinks combined in the same TextBlock. -->
<TextBlock>
<Hyperlink TextDecorations="None" NavigateUri="http://www.msn.com">MSN Home</Hyperlink>
<Run Text=" | " />
<Hyperlink TextDecorations="None" NavigateUri="http://my.msn.com">My MSN</Hyperlink>
</TextBlock>
只在 MouseEnter 事件的超連結上顯示底線
TextDecoration 物件是您可以新增至文字的視覺裝飾;然而,若進行個體化則非常耗用效能。 如果您大量使用 Hyperlink 元素,請考慮僅在觸發事件時顯示底線,例如 MouseEnter 事件。 如需詳細資訊,請參閱指定超連結是否要加上底線。
下圖顯示 MouseEnter 事件如何觸發加上底線超連結:
顯示 TextDecoration 的超連結
下列標記範例顯示包含和不含底線的 Hyperlink 定義:
<!-- Hyperlink with default underline. -->
<Hyperlink NavigateUri="http://www.msn.com">
MSN Home
</Hyperlink>
<Run Text=" | " />
<!-- Hyperlink with no underline. -->
<Hyperlink Name="myHyperlink" TextDecorations="None"
MouseEnter="OnMouseEnter"
MouseLeave="OnMouseLeave"
NavigateUri="http://www.msn.com">
My MSN
</Hyperlink>
下表顯示 1000 個有無底線之 Hyperlink 元素的效能成本。
超連結 | 建立時間 (毫秒) | 轉譯時間 (毫秒) |
---|---|---|
包含底線 | 289 | 1130 |
不含底線 | 299 | 776 |
文字格式設定功能
WPF 提供 RTF 文字格式設定服務,例如自動斷字。 這些服務可能會影響應用程式效能,只有在必要時才應使用。
避免使用不必要的斷字
自動斷字會尋找文字行的連字號斷點,並允許 TextBlock 和 FlowDocument 物件中行的其他斷點位置。 這些物件預設已停用自動斷字功能。 您可以將物件的 IsHyphenationEnabled 屬性設定為 true
來啟用此功能。 不過,啟用此功能會導致 WPF 起始元件物件模型 (COM) 互通性,這可能會影響應用程式效能。 若非必要,建議您不要使用自動斷字功能。
小心使用圖表
Figure 元素代表可位於一頁內容內絕對位置的部分非固定格式內容。 在某些情況下,若 Figure 的位置與已配置的內容相衝突,則它可能會造成整個頁面自動重新設定格式。在頁面大小固定的情況下,藉由將彼此相鄰的 Figure 項目分組,或在內容頂端附近宣告這些項目,即可將不必要之重新格式化的可能性降至最低。
最佳段落
FlowDocument 物件的最佳段落功能會配置段落,讓空白字元盡量平均分佈。 依預設已停用最佳段落功能。 您可以將物件的 IsOptimalParagraphEnabled 屬性設為 true
,藉此啟用這個功能。 不過,啟用此功能會影響應用程式效能。 若非必要,建議您不要使用最佳段落功能。