最佳化效能:文字

WPF 包含透過使用功能豐富的使用者介面 (UI) 控制項來呈現文字內容的支援。 一般而言,您可以將文字轉譯劃分為三個層級:

  1. Glyphs直接使用 和 GlyphRun 物件。

  2. FormattedText使用 物件。

  3. 使用高階控制項,例如 TextBlockFlowDocument 物件。

本主題提供文字轉譯的效能建議。

在圖像層級轉譯文字

Windows Presentation Foundation (WPF) 提供進階文字支援,包括圖像層級標記,可直接存取 Glyphs 想要在格式化後攔截和保存文字的客戶。 這些功能可針對下列每個案例中的不同文字轉譯需求提供重要支援。

  • 固定格式文件的螢幕顯示。

  • 列印案例。

    • 可延伸的應用程式標記語言 (XAML) 作為裝置印表機語言。

    • Microsoft XPS 檔寫入器。

    • 先前的印表機驅動程式,從 Win32 應用程式輸出為固定格式。

    • 列印多工緩衝處理格式。

  • 固定格式的檔標記法,包括舊版 Windows 和其他計算裝置的用戶端。

注意

GlyphsGlyphRun 是針對固定格式的檔簡報和列印案例所設計。 WPF 針對一般配置和使用者介面 (UI) 案例提供數個元素,例如 LabelTextBlock 。 如需版面配置和 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 中轉譯文字最有效率的方式是使用 GlyphsGlyphRun 在圖像層級產生文字內容。 不過,此效率的成本是遺失容易使用的 RTF 格式設定,這是 Windows Presentation Foundation (WPF) 控制項的內建功能,例如 TextBlockFlowDocument

FormattedText 物件

物件 FormattedText 可讓您繪製多行文字,其中文字中的每個字元都可以個別格式化。 如需詳細資訊,請參閱繪製格式化的文字

若要建立格式化的文字,請呼叫建 FormattedText 構函式來建立 FormattedText 物件。 建立初次格式化的文字字串之後,您就可以套用一系列的格式化樣式。 如果您的應用程式想要實作自己的配置,則 FormattedText 物件比使用 控制項更好,例如 TextBlock 。 如需 物件的詳細資訊 FormattedText ,請參閱 繪製格式化文字

FormattedText物件提供低階文字格式設定功能。 您可以將多個格式化樣式套用到一或多個字元。 例如,您可以呼叫 SetFontSizeSetForegroundBrush 方法來變更文字中前五個字元的格式。

下列程式碼範例會 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 是可重新流動的檔容器,可支援豐富的內容呈現,因此,其效能影響大於使用 TextBlockLabel 控制項。

如需 的詳細資訊 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 來設定文字屬性

一般而言,在 Run 中使用 TextBlock 會比完全不使用明確 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 TextBlock 個具有 和 沒有明確 Run 之 物件的成本。

TextBlock 類型 建立時間 (毫秒) 轉譯時間 (毫秒)
Run 設定文字屬性 146 540
TextBlock 設定文字屬性 43 453

避免資料繫結至 Label.Content 屬性

假設您有 Label 經常從 String 來源更新的物件案例。 當資料將 Label 元素的 Content 屬性系結至 String 來源物件時,您可能會遇到效能不佳。 每次更新來源 String 時,都會捨棄舊 String 物件並重新建立新的 String 物件,因為 String 物件是不可變的,所以無法修改。 這又會導致 ContentPresenterLabel 物件的 捨棄其舊內容,並重新產生新內容以顯示新的 String

這個問題的解決方法很簡單。 Label如果未設定為自訂 ContentTemplate 值,請將 取代 LabelTextBlock ,並將 屬性 Text 系結至來源字串。

資料繫結屬性 更新時間 (毫秒)
Label.Content 835
TextBlock.Text 242

物件 Hyperlink 是內嵌層級的流程內容專案,可讓您在流程內容中裝載超連結。

您可以將多個 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>

TextDecoration物件是您可以新增至文字的視覺裝飾;不過,具現化會耗用效能。 如果您廣泛使用 Hyperlink 元素,請考慮只在觸發事件時顯示底線,例如 MouseEnter 事件。 如需詳細資訊,請參閱指定超連結是否要加上底線

下圖顯示 MouseEnter 事件如何觸發加底線超連結:

Hyperlinks displaying TextDecorations

下列標記範例顯示 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 格式設定服務,例如自動斷字。 這些服務可能會影響應用程式效能,只有在必要時才應使用。

避免使用不必要的斷字

自動斷字會尋找文字行的連字號中斷點,並允許 和 FlowDocument 物件中 TextBlock 行的其他中斷點。 這些物件預設已停用自動斷字功能。 您可以將物件的 IsHyphenationEnabled 屬性設定為 true 來啟用此功能。 不過,啟用此功能會導致 WPF 起始元件物件模型 (COM) 互通性,這可能會影響應用程式效能。 若非必要,建議您不要使用自動斷字功能。

小心使用圖表

元素 Figure 代表流程內容的一部分,該部分可以絕對放置在內容頁面內。 在某些情況下,如果頁面的位置與已經配置的內容相衝突, Figure 可能會導致整個頁面自動重新格式化。您可以將彼此連續的元素分組 Figure ,或在固定頁面大小案例中將其宣告在內容頂端附近,以將不必要的重新格式化的可能性降到最低。

最佳段落

物件的最佳段落功能 FlowDocument 會配置段落,以便盡可能平均地散發空白字元。 依預設已停用最佳段落功能。 您可以將 物件的 IsOptimalParagraphEnabled 屬性設定為 true ,以啟用此功能。 不過,啟用此功能會影響應用程式效能。 若非必要,建議您不要使用最佳段落功能。

另請參閱