The problem

When we use Runs in a TextBlock in XAML, we can get these annoying whitespaces between the Runs in our application. For example, this XAML…

… produces this in our App…

Output - Whitespaces


You see these whitespaces in between? I know you do!
If you look at the Visual Tree, you’ll see that there are more Runs in the TextBlock than those that I put in XAML:

TextBlock Inlines


What kind of sorcery is this?

Did you know that the following XAML will also perfectly work?

This would output something like this: “123 foo 456 bar 789”.

Once you know that and you know how XAML processes whitespaces (there is an article on MSDN  about this). It should become clear why the previous result had these extra Runs with only a whitespace between my Runs.

If I’d write the following (without whitespaces between my Runs), I wouldn’t see these extra Runs in my App:

This would put “123456789” on my screen, without any whitespace between them, because there is no whitespace in XAML either.

But for readability and stuff I’d really like to put Runs under each other….

An Attached Property to the rescue

I’ve written an Attached Property that provides a fix for this kind of behavior.


This would result in something like this: “123456789 foobar” (notice the space between the numbers and ‘foobar’, which I explicitly defined in XAML).

How it works

I’ve created two Attached Properties to make this work. The first one it the RemoveEmptyRuns attached property which can be defined on a TextBlock. When this is set to ‘true’, at runtime, when the TextBlock is loaded, I’m going to remove all Runs that are empty of have a whitespace from the TextBlock’s Inlines collection:

In the above code you’ll see this ‘GetPreserveSpace’ thing which I call. Well, that’s the second Attached Property I’ve built. This PreserveSpace attached property can be used on a Run to identify that the programmer has intentionally added this Run (with only a whitespace) to the TextBlock. That way I prevent throwing away spaces that were added on purpose to the TextBlock.


I updated my code. I used to check the following:

But this check is not OK! If the TextProperty of a particular Run is bound to a property of my ViewModel for example, then it’s value can be “” (empty string)  if the data was not yet bound. Causing the Run to be removed from the Inlines of my TextBlock.
That’s why I now only explicitly check on a whitespace instead of String.IsNullOrWhiteSpace:


More code

This is the entire code of the two Attached Properties:

You can find everything, as usual, on GitHub!