I have a TextBlock
in WPF application.
The (Text
, Width
, Height
, TextWrapping
, FontSize
, FontWeight
, FontFamily
) properties of this TextBlock
is dynamic (entered by the user at the runtime).
Every time the user changes one of the previous properties, the Content
property of the TextBlock
is changed at the runtime. (everything is ok until here)
Now, I need to get the lines of that TextBlock
according to the previously specified properties.
That means I need the lines that TextWrapping
algorithms will result.
In other words, I need each line in a separated string or I need one string with Scape Sequence \n
.
Any Idea to do that?
I would have been surprised if there is no public way of doing that (although one never knows, especially with WPF).
And indeed looks like TextPointer class is our friend, so here is a solution based on the TextBlock.ContentStart, TextPointer.GetLineStartPosition and TextPointer.GetOffsetToPosition:
There is not much to explain here
Get the start position of the line, subtract the start position of the previous line to get the length of the line text and here we are.
The only tricky (or non obvious) part is the need to offset the
ContentStart
by one since by designThe TextPointer returned by this property always has its LogicalDirection set to Backward.
, so we need to get the pointer for the same(!?) position, but withLogicalDirection set to Forward
, whatever all that means.With
FormattedText
class, the formatted text can be first created and its size evaluated, so you know the space it takes in a first step, If it's too long, it's up to you to split in separate lines.Then in a second step, it could be drawn.
Everything could happen on the
DrawingContext
object in the following method :Here is the CustomControl solution :
Usage of that control (border is here to show effective clipping) :
If it is not a problem you can use reflection on the TextBlock control (it of course knows how the string is wrapped). If you are not using MVVM, I guess it is suitable for you.
First of all I created a minimal window for testing my solution:
Now let's see the most important part of the code-behind:
The
GetLineMetrics
method retrieves a collection of LineMetrics (an internal object, so I cannot use it directly). This object has a property called "Length" which has the information that you need. So theGetLength
method just read this property's value.Lines are stored in the list named
tokens
and showed by using theTextBox
control (just to have an immediate feedback).I hope my sample can help you in your task.