Utiliser les bindings compilés (x:Bind) depuis un dictionnaire de ressources
Windows 10 nous a apporté une nouvelle extension de balisage x:Bind .
L'avantage de ces bindings, évalués à la compilation, est une amélioration des performances comparé à l'ancien type de liaison Binding.
On aurait donc tendance à remplacer toutes nos utilisations du bon vieux Binding par des x:Bind. Cela veut dire également remplacer ces usages dans les datatemplate et les dictionnaries de ressources.
Le problème
Mais voilà, une particularité à l'utilisation de ces binding évalués à la compilation, c'est qu'ils génèrent du code. Et nos dictionnaires de ressources n'ont pas de code-behind. Cela provoque une exception lors de la compilation.
Voyons un exemple pour reproduire, puis résoudre le problème. Pour la solution aller directement ici.
Imaginons que l'on ait une classe simple représentant nos données :
namespace XBindResourcesSample { public class Item { public string Label { get; set; } } }
Pour tester notre affichage nous avons le code suivant dans la page principale :
public sealed partial class MainPage : Page { ObservableCollection<Item> Items = new ObservableCollection<Item>(); public MainPage() { this.InitializeComponent(); } private void MainPage_Loaded(object sender, RoutedEventArgs e) { for (int index = 0; index < 10; index++) { Items.Add(new Item { Label = "My Label" }); } } }
Nous avons enfin besoin d'un fichier de ressource Templates.xaml qui est bien évidemment référencé dans les ressources définies dans le fichier App.xaml :
Templates.xaml
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:XBindResourcesSample"> <DataTemplate x:Key="ItemDataTemplate" x:DataType="local:Item"> <TextBlock x:Name="Label" Text="{x:Bind Label}"/> </DataTemplate> <!-- Code fonctionnel : <DataTemplate x:Key="ItemDataTemplate"> <TextBlock x:Name="Label" Text="{Binding Label}"/> </DataTemplate>--> </ResourceDictionary>
App.xaml
<Application.Resources> <ResourceDictionary> <ResourceDictionary.MergedDictionaries> <ResourceDictionary Source="Templates.xaml" /> </ResourceDictionary.MergedDictionaries> </ResourceDictionary> </Application.Resources>
Voilà le problème qui survient si l'on remplace simplement un Binding par un x:Bind dans un dictionnaire de ressources :
This Xaml file must have a code-behind class to use {x:Bind}.
Quelques modifications sont donc nécessaires pour faire fonctionner nos x:Bind dans des dictionnaires de ressources.
La solution
Pour résoudre notre problème on va donc faire plaisir à notre compilateur en ajoutant une classe Templates.xaml.cs qui sera donc le code behind de notre dictionnaire de ressources.
En choisissant le même nom que celui de votre dictionnaire en rajoutant .cs vous verrez que l'association sera automatique.
Dans le code de la classe rendons la partial et ajoutons surtout InitializeComponent dans le constructeur qui sera utilisé pour charger le dictionnaire :
namespace XBindResourcesSample { public partial class Templates { public Templates() { InitializeComponent(); } } }
Dans le dictionnaire de ressources il faut alors ajouter le lien à cette classe : x:Class="XBindResourcesSample.Templates".
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:XBindResourcesSample" x:Class="XBindResourcesSample.Templates">
Ne nous reste alors qu'à changer notre façon de référencer ce dictionnaire de ressource depuis les ressources de l'application dans le fichier App.xaml.
<ResourceDictionary.MergedDictionaries> <local:Templates/> </ResourceDictionary.MergedDictionaries>
Et voilà !
A la prochaine compilation vous aurez la joie de ne plus avoir d'erreur et de voir apparaître les binding dans le code généré :
Commentaires