Using compiled bindings in Xamarin.Forms
As a Xamarin developer, you have surely come across a scenario where you’ve mistyped a binding and didn’t figure it out until hours later. Let’s see if we can improve that with XAML compilation and compiled bindings!
One part of improving this scenario is to enable XAML compilation. It is off by default, meaning that creating a new project doesn’t enable it for you yet. This is due to Xamarin wanting to ensure backwards compatibility. Adding support for XAML compilation is as simple as adding one line enabling it somewhere in your app. Most people decorate their
App.xaml.cs with it.
But what does it do? The most important part is that it checks your XAML files for errors during compile time immediately notifying you of any errors you made. Did you accidentally type
SnackLayout instead of
StackLayout? Without XAML compilation enabled you would still be able to run your app and it would either crash or simply not render your UI as it should.
With XAML compilation enabled, you will see errors in your XAML files pop up in the Errors pane after your build has completed. This allows for quick and easy spotting of errors in your XAML. Additionally XAML compilation also reduces assembly file size and instantiation time for your XAML files.
Getting started with compiled bindings
We’ve added XAML compilation to help us spot errors in our XAML files, but unfortunately, this does not extend into bindings. We can still mess them up and wouldn’t be aware of it until we see potential errors appear at runtime. This is where compiled bindings will help us.
Regular bindings use reflection to be resolved at runtime, which makes it impossible to do compile-time validation. This process of reflection is also not a very cost-effective process and could add unnecessary overhead depending on the platform. Since compiled bindings resolve at compile-time a developer can quickly spot incorrect binding expressions. Enabling compiled bindings is simple:
- Enable XAML compilation as shown in the previous section.
- Use the
x:DataTypeattribute to provide the data type of the binding context of a
x:DataType attribute takes a type name as a string or you can use the
x:Type extension to provide a type. The binding context of the element to which you apply
x:DataType will be assumed to be the type you provide here. Looking at the sample code below we set the
BindingContext of the page to an instance of
MainViewModel. By also setting the
x:DataType we automatically get compile-time binding validation on every element below this root element. If the
KidsName property does not exist on the
MainViewModel or we mistype its name we will see an error in our error pane.
Compiled bindings and DataTemplate
As a mobile developer, you have very likely used a templated control at some point. Be it to show items in a list or a fancy carousel. As you may know, these types of controls that take a collection as input use their own data context where each item is bound to an item in the collection. Using
x:DataType on a higher level in the view hierarchy would not work in this situation.
Luckily, to fix this, we can apply
x:DataType on the
DataTemplate element. Since it can be applied and redefined anywhere in the view hierarchy this will work exactly the same as shown before. Here’s a small code sample using
If a property named
Description does not exist in the
ItemViewModel class the compiler will now throw an error. As you can see, adding
x:DataType where applicable can really make your life a lot easier when it comes to setting up bindings.
Why not just use these everywhere?
There are some scenarios where compiled bindings won’t work. One example is when using the
Source attribute on a binding. This attribute cannot be resolved at compile-time, so bindings with the
Source attribute are excluded as compiled bindings by design. Nevertheless, it’s good practice to set the
x:DataType attribute at the same level in the view hierarchy as the
BindingContext is set. Your developer experience will definitely benefit from it.