How to use compiled bindings (x:Bind) from a resource dictionary

How to use compiled bindings (x:Bind) from a resource dictionary

Compiled bindings (often just referred to as x:Bind) is a new type of binding mechanism in Windows 10 Universal Windows Platform (UWP) which does all the heavy lifting during compile time, instead of doing it during runtime via reflection, which improves performance significantly but also has some other benefits such as strong typing and compile time validation (no more typos in binding expressions and then scratching your head and going through Output window trying to figure out why something isn't being shown in the UI).

The "old" {Binding } mechanism still remains and has to be used for certain scenarios. The best resource for tackling compiled bindings at this time is Build 2015 session by Sam Spencer available on Channel 9 called Data Binding: Boost Your Apps' Performance Through New Enhancements to XAML Data Binding so I highly recommend it if you want to dive in.

One problem now is that since the bindings are being evaluated at compile time, there's also code being generated in partial classes, which may make you wonder - how do I use compiled bindings inside data templates from a resource dictionary, as that is a great way to define static resources shared across different pages and user controls?

Three steps are needed to get it to work.

Note that that everything here is written using Windows 10 Technical Preview build 10130 and Technical Preview Tools, so things can change.

Before we go through the mentioned steps, let's set things up and show what the problem is. Let's define a simple Speaker class with a couple of public properties and a Speaker data template.

public class Speaker  
{
    public string Company { get; set; }
    public string Name { get; set; }
    public string ProfileImage { get; set; }
}

Speaker data template is defined inside a ResourceDictionary called DataTemplates.xaml.

Adding a ResourceDictionary

<ResourceDictionary  
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:xBindResourceDictionary">

    <DataTemplate x:Key="SpeakerDataTemplate" x:DataType="local:Speaker">
        <RelativePanel>
            <Image x:Name="ProfileImage" 
                   Source="{x:Bind ProfileImage}"
                   RelativePanel.AlignVerticalCenterWithPanel="True" 
                   Stretch="Uniform" 
                   MaxHeight="100"/>
            <TextBlock x:Name="Name" 
                       Margin="10,0"
                       Text="{x:Bind Name}" FontSize="28"
                       RelativePanel.AlignTopWith="ProfileImage"
                       RelativePanel.RightOf="ProfileImage" />
            <TextBlock x:Name="CompanyName"
                       Margin="10,0"
                       Text="{x:Bind Company}"
                       RelativePanel.Below="Name"
                       RelativePanel.RightOf="ProfileImage"/>
        </RelativePanel>
    </DataTemplate>
</ResourceDictionary>  

MainPage code-behind is very simple:

public sealed partial class MainPage : Page  
{
    ObservableCollection<Speaker> speakers = new ObservableCollection<Speaker>();

    public MainPage()
    {
        this.InitializeComponent();
        this.Loaded += MainPage_Loaded;
    }

    private void MainPage_Loaded(object sender, RoutedEventArgs e)
    {
        for (int index = 0; index < 20; index++)
        {
            speakers.Add(new Speaker
            {
                Name = "Bugs Bunny",
                Company = "Looney Tunes",
                ProfileImage = "https://upload.wikimedia.org/wikipedia/en/2/26/Classic_bugsbunny.png"
            });
        }
    }
}

Notice two important things here - first of all, the list of speakers will only contain one speaker (20 times) - Bugs Bunny (as if he'd be interested in speaking at a conference in the first place :) ). Also, ObservableCollection is a private field in the MainPage! x:Bind takes the page (or user control) as data context and allows binding to fields!

The MainPage XAML is even simpler:

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">  
    <ListView ItemsSource="{x:Bind speakers}"
              ItemTemplate="{StaticResource SpeakerDataTemplate}"/>
</Grid>  

Try to build it, and it won't work! So, here are the three steps needed to fix this!

Create a class

Create a public partial class called, for example, DataTemplates.cs. In the class constructor, call InitializeComponent() method.

public partial class DataTemplates  
{
    public DataTemplates()
    {
        InitializeComponent();
    }
}

Link the class to the resource dictionary

Change the resource dictionary that you defined earlier by setting the class: x:Class="xBindResourceDictionary.DataTemplates"

<ResourceDictionary  
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:xBindResourceDictionary"
    x:Class="xBindResourceDictionary.DataTemplates">

//// the rest of the resource dictionary

Ensure that the dictionary is loaded

Create an instance of the resource dictionary, making sure that the InitializeComponent() gets called. For example, merge the App.xaml ResourceDictionary with the one you defined called DataTemplates:

<Application  
    x:Class="xBindResourceDictionary.App"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:xBindResourceDictionary"
    RequestedTheme="Light">

    <Application.Resources>
        <ResourceDictionary>
            <DataTemplate x:Key="SomeOtherTemplate">
                //// some other code
            </DataTemplate>

            <DataTemplate x:Key="SomeOtherIrrelevantTemplate">
                //// some other code
            </DataTemplate>

            <ResourceDictionary.MergedDictionaries>
                <local:DataTemplates/>
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Application.Resources>
</Application>  

When you build the app, you can dig into DataTemplates.cs file and see that the data binding code is generated:

Code-behind generated compiled bindings

If you try running the app now, it just works!

App runs, compiled bindings work

Conclusion

Compiled bindings are a great new mechanism to improve your XAML performance. However, most of the time you can't just replace {Binding } with {x:Bind } and expect things to work. The mechanism is different, and in the case of ResourceDictionary, you need to ensure that a backing class exists.

Igor Ralic

igor ralic

View Comments
Microsoft Certified Solutions Developer: Windows Store Apps in C#