#UWPXAML – Compiled Binding – What is it?

Coming with Windows 10 are a lot of new features especially for XAML when creating a Universal Windows Platform application aka. UWP app. We can mention a few of them: new controls (as the RelativePanel, the SplitView and more); new tools for building responsive and adaptive UI (AdaptiveTrigger, Extension SDKs, etc.); and a new way to bind data to the UI, Compiled Binding.

This series on Compiled Binding will be composed of several parts:

 

A quick refresh on Classic Binding

Before going into details about Compiled Binding, let’s get a refresh on “classic” binding.

If you ever have developed a XAML app (with WPF, Silverlight, Windows Phone or Windows 8 Store App), you’ll be most likely familiar with classic data binding.

It uses the {Binding} syntax to pass, observe and update an underlying data to the view easily, therefore simplifying separation of concerns: the view doesn’t have to know about the data, retrieve and update logic being handled by a binding source object created by {Binding} thus making it best used with the MVVM pattern.

Here’s a code sample using classic binding:

MainPage.xaml.cs

public sealed partial class MainPage : Page
{
    public MainPage()
    {
        this.InitializeComponent();
        this.DataContext = new Person() { LastName = "Doe", FirstName = "John" };
    }
}

MainPage.xaml

<StackPanel>
    <TextBlock Text="{Binding LastName}" />
    <TextBlock Text="{Binding FirstName}" />
</StackPanel>

FirstName and LastName here are called paths, they will be resolved at runtime, requiring a small overhead due to the use of reflection.
 

Introducing Compiled Binding

What is Compiled Binding?

Introduced with Windows 10, Compiled Binding is very similar to Classic Binding as it serves the same purpose but with some slight differences.

Compiled Binding is used with the {x:Bind} syntax as opposed to the {Binding} syntax of Classic Binding. It still uses the notifying interfaces (like INotifyPropertyChanged) to watch for changes but {x:Bind} is by default OneTime compared to {Binding} which is OneWay.

The reason for that is that most of the time, you just want to display a value on screen and don’t need it to change over the lifetime of your page. Setting binding to be OneTime by default, remove the need to watch for changes and thus reduce CPU and memory usage.

You can still use OneWay and TwoWay binding, you just need to set it like you normally would with classic binding:

MainPage.xaml.cs

public sealed partial class MainPage : Page
{
    public Person Person = new Person() { LastName = "Doe", FirstName = "John" };

    public MainPage()
    {
        this.InitializeComponent();
    }
}

MainPage.xaml

<TextBlock Text="{x:Bind Person.LastName, Mode=OneWay}" />
<TextBox Text="{x:Bind Person.FirstName, Mode=TwoWay}" />

The main difference, as the name implies, is that the binding is actually « compiled », the paths are resolved at compile-time rather than runtime like classic binding, this permits to have a better troubleshooting experience (mistyped or invalid paths are treated as build error instead of just outputting an error message in the console) and remove the overhead due to reflection usage, which are both great.

This compilation is achieved by code generation. When you use {x:Bind} instead of {Binding}, the compiler will add logic into the « .xaml.g.cs » file corresponding to your « .xaml » file.

Data binding with {x:Bind} has another feature that {Binding} doesn’t have: incremental rendering of the items in ListViewBase-derived controls like ListView and GridView. This is done by using both {x:Bind} and the attribute x:Phase on controls inside your DataTemplate.

<DataTemplate x:DataType="local:Person">
    <StackPanel>
        <TextBlock Text="{x:Bind LastName}" />
        <TextBlock Text="{x:Bind FirstName}" x:Phase="1" />
    </StackPanel>
</DataTemplate>

Based on the ContainerContentChanging event that came with Windows 8.1, x:Phase allows you to progressively render your DataTemplate inside long list of data while the user is scrolling fast.

As you can see in the example, just set the x:Phase attribute on an x:Bind databound element and its rendering will be delayed until the CPU will have more time for it. If no phase is set, it’s by default phase 0, so whenever the item can be rendered, the element will also be.

That way, you have control on what to display first instead of just showing a placeholder. Used effectively, this can greatly enhanced your app’s user experience.

And finally, {x:Bind} is also capable to bind event handlers to events.

With classic binding, this was only possible by using ICommand to bind ViewModel’s methods to a Button click. If you wanted to bind to an event with no corresponding built-in Command property, you had to use a behavior and Interactions library from Blend SDK, usually you had to use EventToCommand behavior from MVVM libraries like MVVMLight.

One important thing to note also is that while classic binding uses the property DataContext as a root source for evaluating binded paths, Compiled Binding on the other hand directly references the root control in which it is used. For example, when using compiled binding in a page like MainPage, {x:Bind HelloWorld} will reference MainPage.HelloWorld. A field, a property or a method named HelloWorld must exist on MainPage and must be public. This also works when using compiled binding in a UserControl.

We’ll see in the next section a more complete comparison between {x:Bind} and {Binding}.

NB: Compiled Binding is only available for Windows 10 Universal apps (UWP). There is actually no plan to port it to WPF or Windows 8 apps in the future.

 

{Binding} versus {x:Bind}

Here’s a non-exhaustive list of differences between classic binding and compiled binding:

Classic Binding Compiled Binding
Creation Runtime Compile-time
Syntax {Binding LastName} {x:Bind LastName}
Root path context DataContext Root control (Page, UserControl, etc.)
Default mode OneWay OneTime
Invalid path Silently output an error in the console at runtime Build error
INotifyPropertyChanged
INotifyCollectionChanged
Supported Supported
Converters Supported Supported
Duck typing Supported Not supported
Dynamic creation (in code behind) Supported Not supported

Compiled Binding is missing some features from classic binding like Source, UpdateSourceTrigger, TemplatedParent, etc. If you really need these features, you should stick with classic binding when necessary.

RelativeSource=Self is a special case, the keyword itself is missing in compiled bindings but you just need to rewrite your binding because {x:Bind} has access to the root control instance and so has access to every named control in that root control.

RelativeSource with classic binding:

<TextBlock x:Name="TestClassicBinding" Text="{Binding RelativeSource={RelativeSource Mode=Self}, Path=Name}" />

RelativeSource with compiled binding:

<TextBlock x:Name="TestCompiledBinding" Text="{x:Bind TestCompiledBinding.Name}" />

For a more complex use like binding to an unknown ancestor, stick with classic binding and RelativeSource.
 

Can I use both Compiled Binding and Classic Binding in a single project?

Of course you can!

As I said earlier, {x:Bind} only notifies the compiler to add some logic to handle passing a data to the UI that does not need usage of reflection at runtime like {Binding}.

Classic Binding is still available for UWP apps and is sometimes needed to achieve something Compiled Binding does not support such as Duck Typing, where you just know the property names but don’t know about the source object’s type (example : Property « Age » of classes Person and Wine).

It’s welcome when porting existing Windows 8 apps to Windows 10.

You can even use both bindings on a single control:

<TextBlock Text="{x:Bind Person.LastName}" Foreground="{Binding LastNameForegroundColor}" />

But Compiled Binding is currently only available for Universal Windows Platform projects.
 

When should I use Compiled Binding over Classic Binding?

Well, mostly anytime you can.

It really is a great way to enhance your app’s performance and simplify it a little (ICommand no more necessary) while remaining as easy to use as classic binding and as a bonus, troubleshooting becomes easier thanks to compile-time check of your paths!

Classic Binding is still there for you to use. It’s useful when you’re porting a previous Windows 8 app to Windows 10, or when you need advanced features only achievable without knowing the binded type at compile-time (for example, when you are dynamically loading XAML in your app or when your DataTemplate can be used with multiple types not having necessarily a common ancestor)
 

Binding to data

That’s all for introduction on compiled binding.
Head to « Part 1: Binding to data » to learn about how to use compiled binding with data.

Laisser un commentaire

Entrez vos coordonnées ci-dessous ou cliquez sur une icône pour vous connecter:

Logo WordPress.com

Vous commentez à l'aide de votre compte WordPress.com. Déconnexion / Changer )

Image Twitter

Vous commentez à l'aide de votre compte Twitter. Déconnexion / Changer )

Photo Facebook

Vous commentez à l'aide de votre compte Facebook. Déconnexion / Changer )

Photo Google+

Vous commentez à l'aide de votre compte Google+. Déconnexion / Changer )

Connexion à %s