It also shows just how flexible the TextBlock now is, since the introduction of Runs. Each Run can have different styles, cursors, even events like MouseLeftButtonDown
For this scenario, a WPF Forum poster wanted to know how to wrap blocks of text into one group, to make a single paragraph. This project shows two methods in four examples, the WrapPanel and TextBlock Runs. Both are useful concepts to understand, as they each have their uses.
1) Firstly an example of the WrapPanel, which is a great container, a very useful control:
<
WrapPanel
Margin
=
"10"
>
<
TextBlock
Margin
=
"0,0,4,0"
Text
=
"This is an example"
/>
<
TextBlock
Margin
=
"0,0,4,0"
Text
=
"with textboxes that line up horizontally"
/>
<
TextBlock
Margin
=
"0,0,4,0"
Text
=
"then wrap by TEXTBLOCK to a new"
/>
<
TextBlock
Margin
=
"0,0,4,0"
Text
=
"line when there is no more space"
/>
<
TextBlock
Margin
=
"0,0,4,0"
Text
=
"pull the window out to"
/>
<
TextBlock
Margin
=
"0,0,4,0"
Text
=
"see it wrap and change"
/>
</
WrapPanel
>
This will produce a bunch of textblocks that do not themselves wrap, and when there is no space, the TextBlock as a whole will jump to the next line.
2) Next here is an example of using the TextBlock.Inlines collection, by manually assigning Runs in XAML:
<
TextBlock
Margin
=
"10"
TextWrapping
=
"Wrap"
><
Run
Text
=
"This is an example"
/><
Run
Text
=
" of a group of"
/><
Run
Text
=
" manually coded runs"
/><
Run
Text
=
" which are parts of a textblock"
/><
Run
Text
=
" and this is probably closer to what you want"
/></
TextBlock
>
This does just what we want, joining the blocks together and breaking on words, not per block.
3) Example three shows how to build the Runs programatically and add them to an existing TextBlock:
var texts =
new
List<
string
> {
"This is an example of building a TextBlock"
,
" programmatically from a collection"
,
" of strings into one flexible wrapping TextBlock"
};
foreach
(var text
in
texts)
tb1.Inlines.Add(
new
Run { Text = text });
4) Finally here is an example of some of the flexibility of this technique, by making two very different Runs which act independantly within a single TextBlock which I create and add to the Visual Tree.
var cm1 =
new
ContextMenu();
cm1.Items.Add(
new
MenuItem { Header =
"Copy"
});
var cm2 =
new
ContextMenu();
cm2.Items.Add(
new
MenuItem { Header =
"Do something else"
});
var run1 =
new
Run
{
Text =
"Hello"
,
Background = Brushes.Yellow,
Foreground = Brushes.Blue,
Cursor = Cursors.Hand,
ContextMenu = cm1,
FlowDirection = System.Windows.FlowDirection.RightToLeft,
FontFamily =
new
FontFamily(
"Courier"
),
FontSize = 20.0D,
FontWeight = FontWeights.Bold,
TextDecorations = TextDecorations.Strikethrough,
ToolTip =
"Run 1"
,
};
run1.MouseLeftButtonDown +=
new
MouseButtonEventHandler(run1_MouseLeftButtonDown);
var run2 =
new
Run
{
Text =
" World"
,
Background = Brushes.LightGreen,
Foreground = Brushes.Red,
Cursor = Cursors.Cross,
ContextMenu = cm2,
FlowDirection = System.Windows.FlowDirection.LeftToRight,
FontFamily =
new
FontFamily(
"Times New Roman"
),
FontSize = 30.0D,
FontWeight = FontWeights.ExtraLight,
TextDecorations = TextDecorations.Underline,
ToolTip =
"Run 2"
,
};
run2.MouseLeftButtonDown +=
new
MouseButtonEventHandler(run2_MouseLeftButtonDown);
var tb2 =
new
TextBlock { Margin =
new
Thickness(10) };
tb2.Inlines.Add(run1);
tb2.Inlines.Add(run2);
sp1.Children.Add(tb2);
In this example, as well as the visual differences, you can hover over EACH TEXT PART and see a different Cursor & Tooltip and even click each block to trigger separate events!
This available in a demo project here.
This small article is part of a series of WPF "How To" articles, in response to real user questions on the MSDN WPF Forum.