Dot.Blog

C#, XAML, WinUI, WPF, Android, MAUI, IoT, IA, ChatGPT, Prompt Engineering

Silverlight : Debug du Binding Xaml

[new:30/08/2012]Ajouté dans Silverlight 5 le debug des bindings en Xaml est une possibilité encore peu utilisée alors qu’elle simplifie beaucoup la recherche et la résolution de bugs. Une bonne raison d’en parler un peu avec un petit exemple.

Binding Xaml

Le Binding en Xaml c’est comme l’oxygène pour un terrien : si vous l’enlevez, tout meurt...

MVVM est par exemple basé totalement sur l’exploitation du Binding.

Mais le Binding Xaml s’apparente à une extension du balisage, une sorte de langage dans le langage. J’ai déjà parlé dans le précédent billet des extensions personnalisées de Binding, vous vous en souvenez forcément. Peut-être avez-vous raté mon (gros) article sur le Binding “Le Binding Xaml, sa syntaxe, éviter ses pièges... (WPF/Silverlight)” paru en avril 2010 et toujours d’actualité ? Je ne saurais que conseiller au lecteur intéressé de se référer à ce papier très complet.

Bref, le Binding c’est essentiel, j’en ai déjà beaucoup parlé (comme de l’Element Binding aussi, en 2009 ce qui ne nous rajeunit pas Sourire).

Le problème du Binding c’est qu’il y a plusieurs façons de s’en servir : soit en le créant par les dialogues de Visual Studio ou de Expression Blend, soit parfois directement en code Xaml.

Dans le premier cas, il y a toutes les chances que le Binding soit correct (syntaxiquement au moins, mais pas forcément fonctionnellement...), dans le second cas s’ajoute la possibilité d’erreurs de frappe ou de confusion entre plusieurs classes ou propriétés.

Bugs sournois

Les bugs de Binding sont sournois par nature. Xaml n’étant pas compilé on voit d’ailleurs ici toute l’hérésie de vouloir développer des applications professionnelles énormes en Html/Js/CSS où rien n’est contrôlé ! Xaml n’échappe pas aux défauts des langages non fortement typés non compilés...

Les erreurs n’interviennent qu’au runtime et parfois elles sont mêmes difficiles à découvrir.

Quant à trouver la cause, c’est un jeu de piste hasardeux et long.

Il serait tellement simple de pouvoir mettre un point d’arrêt sur un binding et de vérifier si l’objet attaché, sa propriété, sont bien ceux qu’on attend...

Point d’arrêt !

Si ce n’est pas la panacée pour débugger tout code Xaml, Silverlight 5 (avec Visual Studio) a ajouté la possibilité de poser des points d’arrêt sur les Bindings.

Et çà change tout.

Exemple

Prenons un projet minimaliste où l’erreur est tout à fait possible. Et voyons comment le debug de Binding peut résoudre les choses en quelques secondes.

Il s’agit d’une application Silverlight 5 “normale” sans fioriture ni framework supplémentaire.

J’ai créé une classe “Book” qui permet de stocker les informations principales d’un livre :

public class Book
{
public string Title {get; set;}
public int Year { get; set;}
public string Author { get; set;}

public override string ToString()
{
return Title + ", " + Author + " (" + Year + ")";
}
}

Rien de bien savant. J’ai surchargé le ToString() pour simplifier l’affichage dans une ListBox sans avoir besoin de créer un DataTemplate. Je cherche la simplicité absolue pour cet exemple.

Dans le constructeur du code-behind de MainPage.xaml je lie le code de la classe MainPage au DataContext global de la page (c’est une forme ultra édulcorée “à l’arrache” de MVVM !) :

public MainPage()
{
InitializeComponent();
DataContext = this;
}

Bien entendu pas de données de Design ici !

Dans ce même code, j’instancie une liste de livres “en dur” avec une propriété publique pour y accéder :

public List<Book> Books
{
get
{
return books;
}
}
private List<Book> books = new List<Book>
{
new Book {Author = "Ray Bradbury",Title = "Chroniques martiennes",Year = 1950},
new Book {Author = "Jack Vance",Title = "Palace of Love",Year = 1967},
new Book {Author = "John T. Sladek",Title = "Roderick",Year = 1980},
new Book {Author = "Catherine Lucille Moore",Title = "Tout smouales étaient les Borogoves",Year = 1943}
};

Un peu de SF à lire pour les vacances si vous ne connaissez pas ces œuvres intéressantes...

Côté Xaml je place une ListBox dans le LayoutRoot, et je lie son ItemsSource à “Books” par Binding. Ce n’est pas ici que les choses vont aller mal alors passons.

Je place ensuite une Grid sous la ListBox. Elle contiendra les informations détaillées du livre sélectionné dans la liste.

Pour faire simple, je fais pointer le DataContext de cette grille sur le SelectedItem de la ListBox. Ce n’est pas là non plus que ça va dérailler.

A l’intérieur de cette grille, je pose des TextBlock, certains servent de labels, les autres vont être liés aux propriétés du livre sélectionné dans la liste.

C’est là qu’on peut facilement faire des bêtises. Autant jusqu’ici toute erreur de Binding sera très voyante (pas d’affichage dans la liste ou pas d’affichage du tout dans la grille de détail), autant dans les détails il va être possible de faire par exemple des fautes de frappes. Et comme la structure de notre exemple n’a aucun support de design pour les données (vous en voyez l’importance...) je vais taper les binding à la main.

Si je lance l’application et que je sélectionne une ligne dans la liste voici ce qu'i s’affiche :

image

La grille de sélection en haut, le détail en-dessous. Malheureusement l’année ne s’affiche pas... Dans cet exemple l’erreur se voit très vite, sur un écran chargé cela peut être plus difficile à détecter d’où l’importante d’une phase d’intégration bien menée. Mais là n’est pas la question. Il y a un binding qui ne marche pas...

<UserControl x:Class="xamldebug.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:xamldebug"
mc:Ignorable="d"
d:DesignHeight="372" d:DesignWidth="557"
DataContext="{Binding RelativeSource={RelativeSource Self}}">

<Grid x:Name="LayoutRoot" Background="White" >
<ListBox Height="145" HorizontalAlignment="Left" Margin="20,16,0,0" Name="listBox1" VerticalAlignment="Top" Width="437" ItemsSource="{Binding Books}"/>
<Grid Height="116" HorizontalAlignment="Left" Margin="20,167,0,0" Name="grid1" VerticalAlignment="Top" Width="352" DataContext="{Binding ElementName=listBox1, Path=SelectedItem}" Background="WhiteSmoke">
<TextBlock Height="23" HorizontalAlignment="Left" Margin="22,17,0,0" Name="textBlock1" Text="Titre" VerticalAlignment="Top" />
<TextBlock Height="23" HorizontalAlignment="Left" Margin="22,46,0,0" Name="textBlock2" Text="Auteur" VerticalAlignment="Top" />
<TextBlock Height="23" HorizontalAlignment="Left" Margin="22,82,0,0" Name="textBlock3" Text="Année" VerticalAlignment="Top" />
<TextBlock Height="23" HorizontalAlignment="Left" Margin="100,14,0,0" Name="textBlock4" Text="{Binding Title}" VerticalAlignment="Top" FontWeight="Bold" />
<TextBlock Height="23" HorizontalAlignment="Left" Margin="100,46,0,0" Name="textBlock5" Text="{Binding Author}" VerticalAlignment="Top" FontWeight="Bold"/>
<TextBlock Height="23" HorizontalAlignment="Left" Margin="100,82,0,0" Name="textBlock6" Text="{Binding Yer}" VerticalAlignment="Top" FontWeight="Bold" />
</Grid>
</Grid>
</UserControl>

Le code Xaml de la fiche est ultra simple et le TextBlock incriminé est le dernier objet déclaré. Un œil habitué à Xaml verra certainement tout de suite d’où vient le problème car ici tout est vraiment super simple...

Imaginons que cela soit plus proche de la réalité, plus complexe, plus difficile à décrypter et que vous soyez charrette, le truc à rendre pour avant-avant-hier, fin de journée dans un open space qui tue la concentration, 2 bonnes heures sup au compteur, tiens la femme de ménage vide les poubelles vous êtes tout seul (heures sup que le patron ne payera pas, forcément vous êtes “cadre” la belle escroquerie !), trois fois que votre nana essaye de vous joindre sur le portable et que vous refusez l’appel pensant terminer dans 5 minutes (depuis trois heures en fait), ça va encore être chaud ce soir en rentrant... Bref, une journée normale d’informaticien Sourire

Dans ces conditions là, la petite coquille en Xaml, elle devient vachement plus difficile à trouver je vous le garantie !

Mais heureusement le Binding depuis Silverlight 5 peut être debugger avec un point d’arrêt !

Plaçons un point d’arrêt sur la ligne du TextBlock récalcitrant, directement dans la page de code Xaml comme on le ferait en C# et lançons le programme...

image

Petit zoom sur la fenêtre “Output” :

image

Il y a une “erreur de chemin d’accès” dans l’expression de Binding sur la propriété “Yer” qui est introuvable sur le livre “Tout smouales étaient...”

Là c’est bon... “Yer” ça n’existe pas. Même fatigué ça n’existe pas. Bourré éventuellement, mais pas de ça chez nous !

Il suffit d’ajouter le “a” qui manque dans le code de Binding pour se lier à la propriété “Year” et tout est ok !

Bien entendu les expressions de binding sont parfois bien plus complexes, avec des sources relatives, ou des Path longs, etc. Pouvoir connaitre immédiatement le détail du Binding qu’on soupçonne d’aller de travers est un vrai gain de temps. D’autant que bénéficiant d’un vrai point d’arrêt nous pouvons utiliser tous les outils de debug pour inspecter les objets (parfois l’erreur ne vient pas de Xaml mais d’un objet sous jacent mal instancié, nul, etc...).

Conclusion

Même s’il n’y a rien de très spectaculaire dans le debug Xaml du Binding, et même si j’ai du ajouter un peu d’humour à ma façon pour rendre le sujet moins triste, il n’en reste pas moins vrai que techniquement c’est une nouvelle possibilité bien pratique qui peut faire gagner beaucoup de temps.

Tout ce qui peut améliorer le debug est toujours le bienvenu.

Stay Tuned !

Faites des heureux, PARTAGEZ l'article !

Commentaires (7) -

  • Jérôme

    09/08/2012 11:34:53 | Répondre

    Des mois que je lis vos articles sans laisser de com, il était temps que je me bouge!
    M. Dahan, j'aime beaucoup ce que vous faites. Si cet article n'est pas le plus révolutionnaire, il a le bon goût d'exister, et de faire une piqûre de rappel à ceux qui avaient enterrer Silverlight trop tôt.
    Et même si parfois vos articles peuvent sembler subjectifs, et tout droits issus d'un MS Guru, force est de constater que vous êtes rarement à côté de la vérité (et je nuance avant tout pour la santé de vos chevilles).
    Bref, vos analyses pertinentes me servent grandement lorsque je dois justifier mes choix pour les technos à base de .net, xaml et Cie, et ça ça n'a pas de prix!
    Merci pour votre apport à la famille .net, et au plaisir de vous lire à nouveau!  

  • Olivier

    09/08/2012 15:20:01 | Répondre

    @Nk54 : je n'ai presque pas d'applis en SL 5, pour des raisons pratiques liées à Blend qui plafonne à SL4 (sauf beta qui a arrêté de fonctionné).
    Il y a aussi le fait que beaucoup d'améliorations concernent l'OOB et que dans ce cas je préfère WPF.
    J'ai donc une majorité de devs, même ceux en cours, que je laisse en niveau SL4.
    Du coup j'ai peu de trucs en SL5 et je n'ai pas encore vu ce problème.
    Le workaround montre que c'est un problème de thread et qu'il faut forcer le propertyChanged sur le thread principal. C'est un "cracra".
    J'ai l'habitude pour toute classe qui supporte INotifyPropertyChanged d'avoir ma propre méthode privée qui fait l'appel à l'event, du coup la solution c'est une ligne uniquement à cet endroit.
    Mais c'est pas très clean leur histoire on voit que l'équipe SL est restreinte en ce moment...

  • Olivier

    09/08/2012 15:49:43 | Répondre

    @Jerôme: Merci pour le petit mot, ça fait toujours plaisir de savoir que ce qu'on écrit est utile à quelques personnes.

    Forcément la conviction peut donner l'impression de "gurutisation". Mais très franchement je conseille la plateforme MS parce qu'elle me semble la meilleure. Tout comme je conseille en ce moment de s'intéresser à Android qui devient incontournable quel que soit l'avenir de MS et de ses produits.
    Ma seule faiblesse, ma seule constance je l'avoue, c'est ma détestation de Apple et de sa culture, son esprit, et sa gestion déplorable basée sur l'enfermement. J'ai été client Apple, il y a longtemps et je ne le serai plus jamais. Sauf si MS les rachète Smile

    Mais l'essentiel et mon seul objectif qui reste modeste c'est que le lecteur puisse en tirer quelque chose d'utile !

  • Claude

    01/10/2012 14:21:05 | Répondre

    Merci Olivier !

Ajouter un commentaire