XAML Compiled Bindings (Xamarin.Forms performance reminder)

Xamarin Development WinUI XAML

5 years ago

Data binding is an excellent feature of the MVVM pattern and allows you to decouple views and view models. Because Xamarin.Forms are MVVM-first, using data binding is a clear choice. However, as data binding uses reflection by default, it can have a negative impact on performance. Luckily, Xamarin.Forms support Compiled Bindings, which are akin to UWP's x:Bind and let the compiler process all bindings during compile-time and then use strongly-typed references at runtime thus improving performance immensely.

The case for compiled bindings

The first question you may ask is "Is it worth the effort?" And the answer is a resounding "Yes!". Consider the following advantages of using compiled bindings over classing data binding:

  • Performance is significantly better - for OneTime bindings, the resolution is approximately 20 times quicker for compiled bindings, with other modes still 8 times faster, this improvement can really be felt with larger XAML pages with many controls.
  • Compile-time confidence - setting up data binding is error-prone, and a simple typo can cause the binding not to work at all and is hard to debug. With compiled bindings, any issue is discovered immediately during compilation so you can be confident that your bindings are (at least referentially) correct. Compiled bindings also help you find out "orphan" bindings that were created previously, but are no longer in use as their bound properties have been removed.

How to

There are two general steps to get compiled bindings working on your XAML page or view:

  1. Enable XAML compilation using attributes
  2. Set x:DataType to appropriate type on an element in your XAML visual tree

If you created your project from the new built-in Visual Studio Xamarin.Forms templates, the likelihood is you can already cross out the first step on the list - XAML compilation is on by default. Otherwise you can turn this setting on either on the assembly level or on the page level. If you want to automatically enable it for all XAML pages and views in the project (which is recommended), you can do so like this:

You can put this attribute anywhere in the root assembly namespace. A good place would be App.xaml.cs. Alternatively, you can enable it selectively on page level:

The second step is to enable compiled bindings by adding the x:DataType attribute to a VisualElement in XAML. The recommendation is to set the attribute on the same level in the view hierarchy as where the BindingContext is set. We need to declare an appropriate XML namespace and then use it in the x:DataType attribute. Suppose your app's name is MyAwesomeApp and you want to create compiled binding to a simple MyAwesomeApp.ViewModels.HomeViewModel class:

In HomePage.xaml we add xmlns:viewModels declaration with the namespace to the root <ContentPage> element and set x:DataType on the same level as well:

The compiled bindings are now up and running on our page. You can verify this by replacing Greeting in the binding by some non-existent property name and building the project. You will be "greeted" with a clear no-go error message:

WrongPropertyName

With compiled bindings, no error will go unnoticed

Using compiled bindings with DataTemplate

Another perfect place for compiled bindings are list controls, where every little performance improvement counts N-times. Luckily, Xamarin.Forms will not leave you in the cold here either - you can just as easily apply the x:DataType attribute to DataTemplate as well:

Switching back to classic bindings

Even though compiled bindings are mature enough for production, you might still encounter some issues. In such cases, you can also selectively disable compiled bindings at any level of the XAML hierarch by setting the x:DataType attribute back to null:

Source code

Example source code for this article is available on my GitHub.SampleApp

Summary

Compiled bindings bring two great advantages over classic bindings in Xamarin.Forms - vast performance upgrade and compile-time checking of bingings. This will definitely improve your developer productivity so enabling them is a smart choice.