#UWPXAML – Compiled Binding – Binding to data

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:

 

Databinding with {x:Bind}

Now that you know what compiled binding is and in what it differs from classic binding, let’s see how to use it in different conditions. If you don’t, see « Part 0: Compiled Binding, what is it? »
 

{x:Bind} over a simple value

To start this series of compiled binding examples, we will see how to bind to a single scalar property.

MainPage.xaml.cs

public sealed partial class MainPage : Page
{
    public string ApplicationTitle = "UWP Series - Compiled Binding";

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

Remember that I said x:Bind’s root context is the instance of control which we are currently declaring in its XAML file?

To bind to a value, we need to define it in the « .xaml.cs » file of the control with the public accessor as x:Bind doesn’t have access to protected/private fields. We don’t set the DataContext property because it’s not the root context of compiled binding.

This is also useful to avoid DataContext with compiled binding as it is of type Object and if you need to access some sub-properties of the type you put in DataContext, x:Bind will require that you define the real type in your path like this « {x:Bind Path=DataContext.(local:User.FirstName)}« , reducing the readability of your XAML.

So here, we define the ApplicationTitle string as a public field, but we can also declare it as a property.

Now that we have access to it with x:Bind in XAML, let’s see how to bind to it.

MainPage.xaml

<Page x:Class="UWPSeries.CompiledBinding.MainPage"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <TextBlock Margin="8" Text="{x:Bind ApplicationTitle}" />
    </Grid>

</Page>

As you can see, it is the same as classic binding, we just have replaced the keyword Binding (also known as Markup Extension) by x:Bind and it works!

Compiled Binding
 

{x:Bind} versus the world

From now on, every code samples will use this Book class.

Book.cs

public class Book
{
    public string ImageUrl { get; set; }
    public string Title { get; set; }
    public string Author { get; set; }
}

 

{x:Bind} over a ViewModel

Using x:Bind with a ViewModel is the same as a scalar data, you can define your ViewModel as a public field/property in your « .xaml.cs » file, and then x:Bind will have access to it in the XAML file.

MainPage.xaml.cs

public sealed partial class MainPage : Page
{
    public Book LastReadBook = new Book
    {
        ImageUrl = "ms-appx:///Images/H2G2_UK_front_cover.jpg",
        Title = "The Hitchhiker's Guide to the Galaxy",
        Author = "Douglas Adams"
    };

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

MainPage.xaml

<Image Source="{x:Bind LastReadBook.ImageUrl}" />
<TextBlock Grid.Column="1" VerticalAlignment="Center">
    <Run Text="{x:Bind LastReadBook.Title}" />
    <LineBreak />
    <Run Text="{x:Bind LastReadBook.Author}" />
</TextBlock>

As you can see, we specify in the binding path the name of the public field we declared in the « .xaml.cs » file followed by a point to access its properties.

Compiled Binding
 

{x:Bind} in a DataTemplate

To use x:Bind in a DataTemplate, there is only one mandatory step. You need to declare to the DataTemplate what will be the type of the context to render. This is done by setting the attribute « x:DataType » on the DataTemplate to the name of the type you will use.

<DataTemplate x:DataType="local:Book">
    <Grid Height="150">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="150" />
            <ColumnDefinition />
        </Grid.ColumnDefinitions>

        <Image Source="{x:Bind ImageUrl}" />
        <TextBlock Grid.Column="1" VerticalAlignment="Center">
            <Run Text="{x:Bind Title}" />
            <LineBreak />
            <Run Text="{x:Bind Author}" />
        </TextBlock>
    </Grid>
</DataTemplate>

One thing: in DataTemplate, the root context of compiled binding is the current item you are trying to render just like with classic binding. So here, when using « {x:Bind Title} », you bind to the current item’s title.

Compiled Binding
 

Special case : {x:Bind} in a ResourceDictionary

When you are creating a DataTemplate, you may want to put it in a separate ResourceDictionary to allow the reuse of this DataTemplate.

But when doing so with compiled binding, you get a build error stating « This Xaml file must have a code-behind class to use {x:Bind}. »

As I said in the previous part, compiled binding is achieved by doing code generation in the « .xaml.g.cs » file linked to your « .xaml » file where you are using x:Bind. But when putting a DataTemplate with compiled binding in a ResourceDictionary, as the dictionary doesn’t have a « .xaml.cs » file, also called a code-behind class, the compiler can’t associate the file generated to your resource dictionary.

To resolve this, you need to create that missing file, to create a partial class that inherits from ResourceDictionary and declare this class with « x:Class » in your ResourceDictionary’s XAML.

DataTemplateResourceDictionary.xaml.cs

public partial class DataTemplateResourceDictionary : ResourceDictionary
{
    public DataTemplateResourceDictionary()
    {
        this.InitializeComponent();
    }
}

DataTemplateResourceDictionary.xaml

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

    <DataTemplate x:DataType="local:Book" x:Key="BookDataTemplate">
        <Grid Height="150">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="150" />
                <ColumnDefinition />
            </Grid.ColumnDefinitions>

            <Image Source="{x:Bind ImageUrl}" />
            <TextBlock Grid.Column="1" VerticalAlignment="Center">
                <Run Text="{x:Bind Title}" />
                <LineBreak />
                <Run Text="{x:Bind Author}" />
            </TextBlock>
        </Grid>
    </DataTemplate>

</ResourceDictionary>

Tip: To simplify this step, you can use the file template « Blank Page » of Visual Studio like you would to create a new page, but once the appropriate files created (« .xaml » and « .xaml.cs »), you change the Page tags to ResourceDictionary tags. All will be set up correctly allowing you to use x:Bind.

Last step is to reference your ResourceDictionary to be used by your application.

As we have created a class to hold the generated binding logic, we can’t use the classic way of declaring ResourceDictionary:

App.xaml

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

    <Application.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="DataTemplateResourceDictionary.xaml" />
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Application.Resources>

</Application>

Instead, we declare it by instantiating it directly.

App.xaml

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

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

</Application>

 

{x:Bind} over another control

x:Bind also has the capability to bind to another control inside the page/usercontrol you are working on, like ElementName and RelativeSource from classic binding.

This is easily done because as we saw in « {x:Bind} over a simple value« , {x:Bind} has access to the page instance. Setting a name to a control make it available in the page’s code-behind in a field of the same name. x:Bind can then use this named control in its path to bind to a property of it.

MainPage.xaml

<TextBox x:Name="InputTextBox" Text="I'm binded" />
<TextBlock Margin="8" Text="{x:Bind InputTextBox.Text, Mode=OneWay}" />

I set the binding as OneWay because x:Bind is by default OneTime and thus not updating when the user starts typing in the textbox.

Compiled Binding
 

Going further

MSDN
« Data binding in depth »
https://msdn.microsoft.com/en-us/library/windows/apps/mt210946.aspx

Channel 9
« Improvements to XAML data binding »
https://channel9.msdn.com/Events/Windows/Developers-Guide-to-Windows-10-RTM/Improvements-to-XAML-data-binding

Build 2015
« Data Binding: Boost Your Apps’ Performance Through New Enhancements to XAML Data Binding » https://channel9.msdn.com/Events/Build/2015/3-635
 

Next time on Compiled Binding: binding to events

Data binding with x:Bind is great like we’ve just seen, but what about event binding?
Head to « Part 2: Binding to events » to learn about how to use compiled binding with events.

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