WPF Standard Control Demo App › TextBlock

TextBlock Display

TextBlock displays read-only text, either a plain string or formatted runs. It is the lightest way to put text on the screen.

Text and Inlines do not mix as one might expect

TextBlock derives from FrameworkElement, not from Control, so it has no template. By default it does not take the focus (Focusable was False), and its text cannot be selected; the article linked below shows how to display selectable read-only text.

Text can be given in two ways: Text as one string, or Inlines such as Run, Bold, and Hyperlink for formatted sentences. A TextBlock whose Inlines (a Run and a Bold) were added before its first layout returned an empty Text, before and after layout, so do not rely on Text of a TextBlock built that way. Setting Text on it afterwards threw no exception; it replaced the formatted runs with a single one.

To combine binding and formatting, bind the Text of a Run instead: a bound Run after a bold “Name: “ showed the bound text and followed the source when it changed.

Long words, limited widths, and padding

TextWrapping defaults to NoWrap. With “Say Supercalifragilisticexpialidocious now” in a width of 100, whose long word alone is wider than 100, NoWrap gave one line cut off at 100. Wrap gave 4 lines, breaking the long word itself. WrapWithOverflow gave 3 lines and kept the word whole, so it ran past 100 and was cut off there. Use Wrap when nothing may run past the edge.

TextTrimming set to CharacterEllipsis or WordEllipsis ends text that does not fit with an ellipsis, as for a name in a column of fixed width; with the default, None, nothing is trimmed. In the measurement, it trimmed in a Grid that limited the width and did nothing in a horizontal StackPanel that did not; limits on the height were not measured. With CharacterEllipsis, a long text was 100 wide in a Grid 100 wide. In a horizontal StackPanel, which gives unlimited width, it took its full width of 220.43, so nothing was trimmed.

Padding defaults to 0. With Padding="10", the TextBlock grew by 20 in each direction, from 61.57 × 15.96 to 81.57 × 35.96.

case measured
base class / Focusable / Padding / TextWrapping, TextTrimming FrameworkElement / False / 0,0,0,0 / NoWrap, None
Inlines "Hello " + Bold "world": Text before / after layout "" / ""
then Text = "Replaced": exception / Inlines count no exception / 1
Run with bound Text after Bold "Name: ": Run.Text / after change "bound" / "changed"
"Say Supercalifragilisticexpialidocious now", width 100: lines NoWrap 1, clipped / Wrap 4 / WrapWithOverflow 3, clipped
CharacterEllipsis: width in Grid 100 / horizontal StackPanel 100 100 / 220.43
Padding=10: size without / with 61.57 x 15.96 / 81.57 x 35.96

Text and inlines, wrapping, trimming, and padding. Measured on .NET 10 / Windows 11.

Why the demo’s lines overlap: LineHeight and LineStackingStrategy

LineHeight sets the height of each line, and LineStackingStrategy how it is applied. The demo app starts at LineHeight 5 with BlockLineHeight, the first value of its combo box. With its four lines, that gave a height of 20 instead of 63.84, so the lines overlap. MaxHeight does not let a line be lower than its text: with 5, the height stayed 63.84. With 30, both gave 120. Use LineStackingStrategy="MaxHeight" or a LineHeight larger than the text to avoid overlapping lines.

LineHeight BlockLineHeight MaxHeight
not set (NaN) 63.84 63.84
5 (demo start) 20 63.84
30 120 120

Height of the demo’s four lines by LineHeight and LineStackingStrategy. Measured on .NET 10 / Windows 11.

Trying it in the demo app

The TextBlock page of the demo app, with the control list on the left and the first section, Text

The TextBlock page of the demo app has sections for Text, TextWrapping, TextTrimming, TextAlignment, Padding, the font properties, Background, Foreground, and LineHeight with LineStackingStrategy. The Text section binds the text to a text box, and the TextAlignment section shows the four values Left, Right, Center, and Justify side by side with wrapping on. The “Show Code” link under each section displays its XAML. The following XAML is the LineHeight section (TextBlockUsageControl.xaml), with the styles and the surrounding GroupBoxes left out and the namespace declarations added. markupextensions is the prefix for the demo app’s own markup extensions:

<StackPanel xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:markupextensions="clr-namespace:WPFStandardControlDemoApp.Common.MarkupExtensions">
  <TextBox x:Name="LineHeightTextTextBox" AcceptsReturn="True"
           Text="TEXTBLOCK&#10;TEXTBLOCK&#10;TEXTBLOCK&#10;TEXTBLOCK" />
  <TextBox x:Name="LineHeightTextBox" Text="5" />
  <ComboBox x:Name="LineStackingStrategyComboBox"
            DisplayMemberPath="Name"
            ItemsSource="{markupextensions:EnumBindingSource EnumType=LineStackingStrategy}"
            SelectedValuePath="Value" SelectedIndex="0" />

  <TextBlock x:Name="LineHeightResultTextBlock"
             LineHeight="{Binding Text, ElementName=LineHeightTextBox}"
             LineStackingStrategy="{Binding SelectedValue, ElementName=LineStackingStrategyComboBox}"
             Text="{Binding Text, ElementName=LineHeightTextTextBox}" />
</StackPanel>

Source code and how it was measured

The defaults, Inlines, the bound Run, wrapping, trimming, Padding, and LineHeight on this page were measured by running them on .NET 10 / Windows 11 (that the text cannot be selected and the TextAlignment values shown in the demo app were not), using TextBlockDemoScene in this site’s screenshot tool. The TextBlocks were laid out with Measure and Arrange. Line counts are the height divided by the height of one line, and “clipped” means WPF’s layout clip cut the TextBlock at the width it was given. Sizes depend on the font and display scaling; they are the values on the measuring machine.

View TextBlock source code on GitHub →