UWP: Compiled Binding - Windows 10 Anniversary Update
Introduction
Coming this summer, Windows 10 Anniversary Update will be more or less a Windows 10 v2.0.
With it comes a lot of new things for the windows app development, and a lot of new features and fixes for Compiled Binding.
Today we'll see what those new features are and how to use them.
If you want to try them out yourself, you'll need a Windows Insider build of Windows 10 with its Windows SDK and create a UWP project targeting a min version at least equals to Build 14383. Do not install it on your main work station, it will break any non-Anniversary Update apps.
For this post, we'll use Windows 10 Build 14383 (available on Fast Ring) with Visual Studio 2015 Update 3.
The Windows SDK for Build 14383 can be found here: https://insider.windows.com/
Function binding
Previously, it was possible to directly bind events to methods which followed specific rules regarding their parameters, but we were unable to bind the result of a method to a property without a converter which was calling the method for us.
Now, it's possible to bind methods directly to properties without the need for a converter! You can provide whatever method you like as long as it has a public accessor and you provide the parameters.
MainPage.xaml.cs
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
}
public string GetHelloWorld()
{
return "Hello World";
}
public Person Roberts = new Person()
{
Firstname = "Dread Pirate",
Lastname = "Roberts"
};
}
Person.cs
public class Person
{
public string Firstname { get; set; }
public string Lastname { get; set; }
public string GetFullname()
{
return $"{Firstname} {Lastname}";
}
}
MainPage.xaml
<TextBlock Text="{x:Bind GetHelloWorld()}" />
<TextBlock Text="{x:Bind Roberts.GetFullname()}" />
The method can have parameters.
You can provide them by setting constants in the XAML or by using data from your ViewModel.
MainPage.xaml.cs
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
}
public DateTime Today = DateTime.Now;
public Person Someone = new Person()
{
Firstname = "Some",
Lastname = "One"
};
public string GetPersonFullname(Person person)
{
return person.GetFullname();
}
}
MainPage.xaml
<TextBlock Text="{x:Bind Today.ToString('d', {x:Null})}" />
<TextBlock Text="{x:Bind GetPersonFullname(Someone)}" />
Does the binding is automatically updated when the data is updated?
Well, it is said to work if you set the Mode of the compiled binding to OneWay/TwoWay (because x:Bind is OneTime by default) but wasn't able to compile it under VS2015.
A few not really understandable compile errors appeared when used TwoWay binding.
Along that, you may notice some errors appearing in the Error list when using parameters inside your binded functions stating "A value does not fall within the expected range". It's a bug of VS2015, but it compiles and runs fine anyway.
Dictionary indexers
As part of supporting most use cases without the need for a converter, x:Bind now supports access to a specific key in a dictionary.
MainPage.xaml.cs
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
}
public Dictionary<string, string> Dictionary = new Dictionary<string, string>()
{
{ "A", "Alpha" },
{ "B", "Beta" },
{ "C", "Charlie" },
};
}
MainPage.xaml
<TextBlock Text="{x:Bind Dictionary['A']}" />
<TextBlock Text="{x:Bind Dictionary['B']}" />
<TextBlock Text="{x:Bind Dictionary['C']}" />
It works great but there is a big shortcoming: You can only use constant strings directly set in the XAML.
Using anything else than a string, like an integer, will result in a compile error.
Even string data from your ViewModel won't work.
Explicit value cast
Contrary to classic Databinding which uses duck typing to check if the binding is valid, compiled binding checks at compile time that the given data matches the property to which it is binded to.
In other words, if the value you're trying to bind has no implicit cast to the type of the property, you can't bind it using x:Bind without a converter.
Even if the value's type declares an explicit cast.
As of the Anniversary Update, you will be able to declare an explicit cast inside a compiled binding, C#-style.
MainPage.xaml.cs
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
}
public bool? IsThreeStateNull = null;
}
MainPage.xaml
<CheckBox Content="IsThreeState = False" IsThreeState="{x:Bind (x:Boolean)IsThreeStateNull}" />
When casting explicitly, you'll need to refer to the class type by its XAML namespace.
In this case, Boolean is part of the "x:" namespace declaration.
Implicit Visibility conversion
Who don't know the legendary BooleanToVisibilityConverter?
Everyone, since the first time WPF came around, implemented it over and over in every projects.
x:Bind no longer requires that, it now converts booleans to Visibility by itself! Hurray!
You just need to bind a boolean to a property like Visibility.
MainPage.xaml.cs
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
}
public bool IsVisibleFalse = false;
public bool IsVisibleTrue = true;
}
MainPage.xaml
<TextBlock Text="I'm not visible!" Visibility="{x:Bind IsVisibleFalse}" />
<TextBlock Text="I'm visible!" Visibility="{x:Bind IsVisibleTrue}" />
Credits
The original post can be found here.
Sample Project
You can find a sample project on GitHub regrouping all the examples we saw in this post: http://github.com/TimLariviere/CompiledBinding-AnniversarySample