Optymalizacja wydajności: tekst

Platforma WPF obejmuje obsługę prezentacji zawartości tekstowej za pomocą kontrolek interfejsu użytkownika (UI, feature-rich user interface). Ogólnie rzecz biorąc, renderowanie tekstu można podzielić na trzy warstwy:

  1. Glyphs Bezpośrednie używanie obiektów iGlyphRun.

  2. FormattedText Korzystanie z obiektu .

  3. Używanie kontrolek wysokiego poziomu, takich jak TextBlock obiekty i FlowDocument .

Ten temat zawiera zalecenia dotyczące wydajności renderowania tekstu.

Renderowanie tekstu na poziomie Glyph

Program Windows Presentation Foundation (WPF) zapewnia zaawansowaną obsługę tekstu, w tym znaczniki na poziomie glyph z bezpośrednim dostępem do Glyphs klientów, którzy chcą przechwycić i utrwalić tekst po sformatowaniu. Te funkcje zapewniają krytyczną obsługę różnych wymagań dotyczących renderowania tekstu w każdym z poniższych scenariuszy.

  • Ekran wyświetlania dokumentów w formacie stałym.

  • Scenariusze drukowania.

    • Extensible Application Markup Language (XAML) jako język drukarki urządzenia.

    • Składnik zapisywania dokumentów w systemie Microsoft XPS.

    • Poprzednie sterowniki drukarek, dane wyjściowe z aplikacji Win32 do stałego formatu.

    • Format buforu wydruku.

  • Reprezentacja dokumentu w formacie stałym, w tym klientów dla poprzednich wersji systemu Windows i innych urządzeń obliczeniowych.

Uwaga

Glyphs i GlyphRun są przeznaczone dla scenariuszy prezentacji i drukowania dokumentów w formacie stałym. Platforma WPF udostępnia kilka elementów dla scenariuszy ogólnego układu i interfejsu użytkownika, takich jak Label i TextBlock. Aby uzyskać więcej informacji na temat scenariuszy układu i interfejsu użytkownika, zobacz Typografia w WPF.

W poniższych przykładach pokazano, jak zdefiniować właściwości obiektu Glyphs w języku XAML. W przykładach założono, że czcionki Arial, Courier New i Times New Roman są instalowane w folderze C:\WINDOWS\Fonts na komputerze lokalnym.

<!-- 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>

Korzystanie z funkcji DrawGlyphRun

Jeśli masz kontrolkę niestandardową i chcesz renderować glify, użyj DrawGlyphRun metody .

WPF udostępnia również usługi niższego poziomu na potrzeby niestandardowego FormattedText formatowania tekstu przy użyciu obiektu. Najbardziej wydajnym sposobem renderowania tekstu w programie Windows Presentation Foundation (WPF) jest generowanie zawartości tekstowej na poziomie glyph przy użyciu metod Glyphs i GlyphRun. Jednak koszt tej wydajności polega na utracie łatwego w użyciu formatowania tekstu sformatowanego, które są wbudowanymi funkcjami kontrolek Windows Presentation Foundation (WPF), takich jak TextBlock i FlowDocument.

Sformatowany obiektText

Obiekt FormattedText umożliwia rysowanie tekstu wielowierszowego, w którym każdy znak w tekście może być sformatowany indywidualnie. Aby uzyskać więcej informacji, zobacz Rysowanie sformatowanego tekstu.

Aby utworzyć sformatowany tekst, wywołaj konstruktor, FormattedText aby utworzyć FormattedText obiekt. Po utworzeniu początkowego sformatowanego ciągu tekstowego można zastosować zakres stylów formatowania. Jeśli aplikacja chce zaimplementować własny układ, FormattedText obiekt jest lepszym wyborem niż użycie kontrolki, takiej jak TextBlock. Aby uzyskać więcej informacji na FormattedText temat obiektu, zobacz Rysunek Sformatowany tekst .

Obiekt FormattedText zapewnia funkcję formatowania tekstu niskiego poziomu. Można zastosować wiele stylów formatowania do co najmniej jednego znaku. Można na przykład wywołać metody i SetForegroundBrush , SetFontSize aby zmienić formatowanie pierwszych pięciu znaków w tekście.

Poniższy przykład kodu tworzy FormattedText obiekt i renderuje go.

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

Kontrolki FlowDocument, TextBlock i Label

WPF zawiera wiele kontrolek do rysowania tekstu na ekranie. Każda kontrolka jest przeznaczona dla innego scenariusza i ma własną listę funkcji i ograniczeń.

FlowDocument ma wpływ na wydajność więcej niż TextBlock lub Label

Ogólnie rzecz biorąc, element powinien być używany, TextBlock gdy wymagana jest ograniczona obsługa tekstu, na przykład krótkie zdanie w interfejsie użytkownika. Label można użyć, gdy wymagana jest minimalna obsługa tekstu. Element FlowDocument jest kontenerem do ponownego przepływu dokumentów, które obsługują bogatą prezentację zawartości, a w związku z tym ma większy wpływ na wydajność niż używanie TextBlock kontrolek lub Label .

Aby uzyskać więcej informacji na temat FlowDocumentprogramu , zobacz Flow Document Overview (Omówienie dokumentu przepływu).

Unikaj używania funkcji TextBlock w elemecie FlowDocument

Element TextBlock pochodzi z elementu UIElement. Element Run pochodzi z TextElementelementu , który jest mniej kosztowny do użycia niż UIElementobiekt pochodny. Jeśli to możliwe, użyj polecenia Run zamiast TextBlock wyświetlania zawartości tekstowej w obiekcie FlowDocument.

Poniższy przykład znaczników ilustruje dwa sposoby ustawiania zawartości tekstowej w obiekcie 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>

Unikaj używania uruchamiania do ustawiania właściwości tekstu

Ogólnie rzecz biorąc, korzystanie z Run wewnątrz obiektu TextBlock jest bardziej intensywnie obciążane niż nie używanie jawnego Run obiektu w ogóle. Jeśli używasz elementu w Run celu ustawienia właściwości tekstu, ustaw te właściwości bezpośrednio na TextBlock zamiast.

Poniższy przykład znaczników ilustruje te dwa sposoby ustawiania właściwości text, w tym przypadku FontWeight właściwość :

<!-- 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>

W poniższej tabeli przedstawiono koszt wyświetlania 1000 TextBlock obiektów z jawnym elementem i bez jawnego Runobiektu .

Typ TextBlock Czas utworzenia (ms) Czas renderowania (ms)
Właściwości tekstu ustawienia uruchamiania 146 540
Właściwości tekstu ustawienia TextBlock 43 453

Unikaj powiązania danych z właściwością Label.Content

Wyobraź sobie scenariusz, w którym masz Label obiekt, który jest często aktualizowany ze String źródła. Gdy dane wiążą Label właściwość elementu Content z obiektem źródłowym String , może wystąpić niska wydajność. Za każdym razem, gdy źródło String jest aktualizowane, stary String obiekt jest odrzucany, a nowy String jest ponownie utworzony — ponieważ String obiekt jest niezmienny, nie można go modyfikować. To z kolei powoduje ContentPresenterLabel odrzucenie starej zawartości obiektu i ponowne wygenerowanie nowej zawartości w celu wyświetlenia nowej Stringzawartości .

Rozwiązanie tego problemu jest proste. Jeśli właściwość Label nie jest ustawiona na wartość niestandardową ContentTemplate , zastąp Label element właściwości a TextBlock i powiąż jej Text właściwość z ciągiem źródłowym.

Właściwość powiązana z danymi Czas aktualizacji (ms)
Label.Content 835
TextBlock.Text 242

Obiekt Hyperlink jest elementem zawartości przepływu wbudowanego, który umożliwia hostowanie hiperlinków w ramach zawartości przepływu.

Użycie wielu Hyperlink elementów można zoptymalizować, grupując je razem w obrębie tego samego TextBlockelementu . Pomaga to zminimalizować liczbę obiektów tworzonych w aplikacji. Na przykład możesz wyświetlić wiele hiperlinków, takich jak:

MSN Home | Moja witryna MSN

Poniższy przykład znaczników przedstawia wiele TextBlock elementów używanych do wyświetlania hiperlinków:

<!-- 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>

Poniższy przykład znaczników przedstawia bardziej wydajny sposób wyświetlania hiperlinków, tym razem przy użyciu pojedynczego TextBlockelementu :

<!-- 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 Obiekt jest ozdobą wizualną, którą można dodać do tekstu, ale może to być intensywne działanie, aby utworzyć wystąpienie. Jeśli używasz szeroko zakrojonych Hyperlink elementów, rozważ pokazanie podkreślenia tylko podczas wyzwalania zdarzenia, takiego jak MouseEnter zdarzenie. Aby uzyskać więcej informacji, zobacz Określanie, czy hiperłącze jest podkreślone.

Na poniższej ilustracji pokazano, jak zdarzenie MouseEnter wyzwala podkreślone hiperłącze:

Hyperlinks displaying TextDecorations

W poniższym przykładzie znaczników pokazano Hyperlink zdefiniowany element z podkreśleniu i bez znaku podkreślonego:

<!-- 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>

W poniższej tabeli przedstawiono koszt wydajności wyświetlania 1000 Hyperlink elementów z podkreśleniami i bez podkreślenia.

Hiperlink Czas utworzenia (ms) Czas renderowania (ms)
Z podkreślem 289 1130
Bez podkreślonia 299 776

Funkcje formatowania tekstu

WPF zapewnia usługi formatowania tekstu sformatowanego, takie jak automatyczne dzielenie wyrazów. Te usługi mogą mieć wpływ na wydajność aplikacji i powinny być używane tylko w razie potrzeby.

Unikaj niepotrzebnego używania dzielenia wyrazów

Automatyczne dzielenie wyrazów znajduje punkty przerwania łącznika dla wierszy tekstu i umożliwia dodatkowe pozycje podziału dla wierszy w TextBlock obiektach i FlowDocument . Domyślnie funkcja automatycznego dzielenia wyrazów jest wyłączona w tych obiektach. Tę funkcję można włączyć, ustawiając właściwość IsHyphenationEnabled obiektu na true. Jednak włączenie tej funkcji powoduje, że WPF inicjuje współdziałanie modelu obiektów składników (COM), co może mieć wpływ na wydajność aplikacji. Zaleca się, aby nie używać automatycznego dzielenia wyrazów, chyba że jest to konieczne.

Ostrożnie używaj rysunków

Element Figure reprezentuje część zawartości przepływu, która może być całkowicie umieszczona na stronie zawartości. W niektórych przypadkach może spowodować automatyczne ponowne sformatowanie całej strony, Figure jeśli jego pozycja zderzy się z zawartością, która została już ułożona. Można zminimalizować możliwość niepotrzebnego ponownego formatowania, grupując Figure elementy obok siebie lub deklarując je w pobliżu górnej części zawartości w scenariuszu o stałym rozmiarze strony.

Optymalny akapit

Optymalna cecha akapitu FlowDocument obiektu określa akapity tak, aby odstępy są rozmieszczone tak równomiernie, jak to możliwe. Domyślnie optymalna funkcja akapitu jest wyłączona. Tę funkcję można włączyć, ustawiając właściwość obiektu IsOptimalParagraphEnabled na true. Włączenie tej funkcji ma jednak wpływ na wydajność aplikacji. Zaleca się, aby nie używać optymalnej funkcji akapitu, chyba że jest potrzebna.

Zobacz też