Monthly Archives: November 2016

Getting rid of whitespaces between Runs in a TextBlock

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.

Usage

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.

 

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

 

 

Compiled bindings gotcha – Don’t forget INotifyPropertyChanged on your interface

Intro

On one of our UWP projects we ran into an issue where OneWay binding using x:Bind (compiled bindings) didn’t work. Only the initial value was shown.

In the end, when I found and fixed the problem, I realized that it was something I actually already knew, but didn’t think about it immediately. I thought I’d share my findings here so it might be of any help if you would run into this issue yourself.

The problem

A colleague was requesting help because he couldn’t get his bindings to work on a case where he was using x:Bind (compiled bindings). He said that the initial value was bound correctly but whenever he changed the value of the property on the ViewModel, the changes where not visible on the view… If he’d change his binding from compiled binding to ‘classic’ binding, everything worked as expected!

The Solution?

So, the first thing I said to my colleague was: “make sure you set the binding mode explicitly to OneWay as compiled bindings default to OneTime (where the BindingMode on ‘classic binding’ defaults to ‘OneWay‘)”. But it turned out that that wasn’t the issue…

Let’s look at it a bit closer

For this blogpost I’ve built a simple app that demonstrates the issue. Let’s quickly look at it.

View:

IMyViewModel:

MyViewModel:

Nothing special about this.

 

I started debugging my colleague’s app and at first sight nothing seemed to be off… Until I stumbled upon this:
PropertyChanged eventhandler Null

The PropertyChanged EventHandler was null and that’s why the changes on the ViewModel aren’t being reflected on the View!

But why? I did define the binding to be OneWay, so I expect the Binding framework to listen to the PropertyChanged event…
Well… That’s actualy true… But is seems something is telling the Binding framework not listen to the PropertyChanged event.

INotifyPropertyChanged

Take a closer look again at the code. The type of the ViewModel property on the View is IMyViewModel (the interface). If we would change this type to the concrete type (MyViewModel), then we notice that everything works as we would expect.

Of course in this sample this wouldn’t be a big issue, but in real life we might want to use interfaces and let the ViewModel be injected at runtime.

Let’s look again at the IMyViewModel. This interface doesn’t implement the INotifyPropertyChanged interface! So at compile time, as we are binding to the interface (instead of a concrete implementation), the binding engine doesn’t know that the concrete implementation will implement the INotifyPropertyChanged interface. The engine can’t generate any code that handles the PropertyChanged-event. And that is exactly the problem in this example!

If we would update our IMyViewModel interface as follows, everything works  as we should expect:

What about ‘classic bindings’?

Well, when using ‘classic bindings’, nothing really happens until runtime. At runtime the binding engine will use some sort of reflection to do the bindings. With compiled bindings -at its name suggests- most of the ‘magic’ happens at compile time: code is being generated that will do all of the binding stuff ‘strongly typed’. And that’s why we don’t have the above issue when using ‘classic bindings’, as the binding engine uses reflection at runtime to do the bindings.

Conclusion

When using compiled bindings and binding to an interface, make sure that not only the concrete implementation implements the INotifyPropertyChanged interface but also that the interface itself implements INotifyPropertyChanged.

You can find the source code I’ve used in the sample on GitHub.