最佳化效能:文字

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

  1. 直接使用 GlyphsGlyphRun 物件。

  2. 使用 FormattedText 物件。

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

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

在字形層級渲染文字

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

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

  • 列印案例。

    • 使用 Extensible Application Markup Language (XAML) 作為裝置印表機語言。

    • Microsoft XPS Document Writer。

    • 先前的印表機驅動程式,從 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 (WPF) 中渲染文字最有效率的方式是使用 Glyphs 和 GlyphRun 在字形層級生成文字內容。 不過,此效率的代價是喪失易於使用的豐富文字格式,這是 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)中的簡短句子。 在需要最少文字支援時,可以使用LabelFlowDocument 元素是可自動重排文件的容器,支援豐富的內容呈現,因此,比使用 TextBlockLabel 控制項有更大的效能影響。

如需關於 流文檔 的詳細資訊,請參閱流文檔概觀。

避免在 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 個帶有及不帶有顯式運行之 TextBlock 物件的成本。

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

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

假設您有一個從String來源頻繁更新的Label物件的情境。 當資料繫結Label元素的Content屬性至String來源物件時,您可能會遇到效能不佳的情況。 每次更新來源 String 時,系統都會捨棄舊的 String 物件並重新建立新的 String,因為 String 物件是不可變的,所以無法修改。 這樣一來,ContentPresenter 物件的 Label 會捨棄其舊內容,重新產生新內容以顯示新的 String

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

資料繫結屬性 更新時間 (毫秒)
標籤.內容 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 事件。 如需詳細資訊,請參閱指定超連結是否要加上底線

下圖顯示滑鼠進入事件如何觸發加上底線的超連結:

顯示文字裝飾的超連結

下列標記語法範例顯示一個 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 個元素,分別為帶有底線和不帶底線的元素,及其效能成本。

超連結 建立時間 (毫秒) 轉譯時間 (毫秒)
包含底線 289 1130
不含底線 299 776

文字格式設定功能

WPF 提供 RTF 文字格式設定服務,例如自動斷字。 這些服務可能會影響應用程式效能,只有在必要時才應使用。

避免使用不必要的連字號

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

小心使用圖表

Figure 元素代表流動內容的一部分,可以在頁面內容中絕對定位。 在某些情況下,若 Figure 的位置與已配置的內容相衝突,則它可能會造成整個頁面自動重新格式化。在頁面大小固定的情況下,藉由將 Figure 元素彼此相鄰進行分組,或在內容頂端附近宣告這些元素,即可將不必要的重新格式化的可能性降至最低。

最佳段落

FlowDocument 物件的最佳段落功能會配置段落,讓空白盡量平均分佈。 預設情況下,最佳段落功能已停用。 您可以透過將物件的 IsOptimalParagraphEnabled 屬性設為 true,來啟用這個功能。 不過,啟用此功能會影響應用程式效能。 若非必要,建議您不要使用最佳段落功能。

另請參閱