TOC

This article has been localized into French by the community.

Data binding:

Déboguer les data bindings

Étant donné que les data bindings sont évalués au moment de l'exécution et qu'aucune exception n'est levée quand ils échouent, un mauvais binding peut parfois être très difficile à trouver. Ces problèmes peuvent survenir dans différentes situations, mais un problème courant est d'essayer de lier une valeur à une propriété qui n'existe pas. Soit parce que vous n'avez pas mémorisé son nom correctement ou parce que vous avez simplement fait une faute de frappe. Voici un exemple :

<Window x:Class="WpfTutorialSamples.DataBinding.DataBindingDebuggingSample"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="DataBindingDebuggingSample" Height="100" Width="200">
    <Grid Margin="10" Name="pnlMain">
		<TextBlock Text="{Binding NonExistingProperty, ElementName=pnlMain}" />
	</Grid>
</Window>

La fenêtre de sortie (Output)

Le premier endroit où vous devriez regarder est dans la fenêtre de sortie (la fenêtre Output) de Visual Studio. Elle devrait se trouver en bas de votre fenêtre de Visual Studio ou sinon vous pouvez l'activer en utilisant le raccourci [Ctrl+Alt+O]. Il y aura des tas de sorties venant du débogueur, mais vous devriez trouver quelque part une ligne de ce genre en exécutant l'exemple ci-dessous :

System.Windows.Data Error: 40 : BindingExpression path error: 'NonExistingProperty' property not found on 'object' ''Grid' (Name='pnlMain')'. BindingExpression:Path=NonExistingProperty; DataItem='Grid' (Name='pnlMain'); target element is 'TextBlock' (Name=''); target property is 'Text' (type 'String')

Ça peut paraître un peu surchargé, surtout dû au fait qu'il n'y a aucun saut de ligne dans ce long message, mais la partie importante est celle-ci :

'NonExistingProperty' property not found on 'object' ''Grid' (Name='pnlMain')'.

Ça dit que vous avez essayé d'utiliser une propriété appelée "NonExistingProperty" sur un objet de type Grid, nommé pnlMain. C'est plutôt clair et cela devrait vous aidez à corriger le nom de la propriété ou à utiliser le binding sur le bon objet si c'est ça le problème.

Ajuster le niveau de traçage

L'exemple précédent était facile à corriger, parce que ce que l'on tentait de faire était clair pour WPF ainsi que pourquoi ça ne marchait pas. Considérez par contre l'exemple suivant :

<Window x:Class="WpfTutorialSamples.DataBinding.DataBindingDebuggingSample"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="DataBindingDebuggingSample" Height="100" Width="200">
    <Grid Margin="10">
		<TextBlock Text="{Binding Title}" />
	</Grid>
</Window>

J'essaye de lier la propriété "Title", mais sur quel objet ? Comme mentionné dans l'article sur les contextes de données, WPF va ici utiliser la propriété DataContext du TextBlock, qui peut être héritée d'un contrôle parent, mais dans cet exemple j'ai oublié d'assigner un contexte de données. En gros ça veut dire que j'essaye d'obtenir une propriété d'un objet NULL. WPF va en déduire que ça pourrait tout à fait être un binding valide mais que l'objet n'a juste pas encore été initialisé et du coup il ne va rien dire à propos de ça. Si vous exécuter cet exemple et que vous regardez dans la fenêtre de sortie (Output), vous ne verrez aucune erreur de binding.

Cependant, pour les cas où ce n'est pas le comportement auquel vous vous attendez, il y a un moyen pour forcer WPF à vous avertir de tous les problèmes de data binding qu'il rencontre. Cela se fait en définissant le TraceLevel de l'objet PresentationTraceSources, que vous pouvez trouver dans le namespace System.Diagnostics :

<Window x:Class="WpfTutorialSamples.DataBinding.DataBindingDebuggingSample"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:diag="clr-namespace:System.Diagnostics;assembly=WindowsBase"
        Title="DataBindingDebuggingSample" Height="100" Width="200">
    <Grid Margin="10">
		<TextBlock Text="{Binding Title, diag:PresentationTraceSources.TraceLevel=High}" />
	</Grid>
</Window>

Remarquez que j'ai ajouté une référence au namespace System.Diagnostics en haut et que j'ai ensuite utilisé la propriété du binding. WPF va maintenant vous donner des tonnes d'informations à propos de ce binding spécifique dans la fenêtre de sortie (Output) :

System.Windows.Data Warning: 55 : Created BindingExpression (hash=2902278) for Binding (hash=52760599)
System.Windows.Data Warning: 57 :   Path: 'Title'
System.Windows.Data Warning: 59 : BindingExpression (hash=2902278): Default mode resolved to OneWay
System.Windows.Data Warning: 60 : BindingExpression (hash=2902278): Default update trigger resolved to PropertyChanged
System.Windows.Data Warning: 61 : BindingExpression (hash=2902278): Attach to System.Windows.Controls.TextBlock.Text (hash=18876224)
System.Windows.Data Warning: 66 : BindingExpression (hash=2902278): Resolving source
System.Windows.Data Warning: 69 : BindingExpression (hash=2902278): Found data context element: TextBlock (hash=18876224) (OK)
System.Windows.Data Warning: 70 : BindingExpression (hash=2902278): DataContext is null
System.Windows.Data Warning: 64 : BindingExpression (hash=2902278): Resolve source deferred
System.Windows.Data Warning: 66 : BindingExpression (hash=2902278): Resolving source
System.Windows.Data Warning: 69 : BindingExpression (hash=2902278): Found data context element: TextBlock (hash=18876224) (OK)
System.Windows.Data Warning: 70 : BindingExpression (hash=2902278): DataContext is null
System.Windows.Data Warning: 66 : BindingExpression (hash=2902278): Resolving source
System.Windows.Data Warning: 69 : BindingExpression (hash=2902278): Found data context element: TextBlock (hash=18876224) (OK)
System.Windows.Data Warning: 70 : BindingExpression (hash=2902278): DataContext is null
System.Windows.Data Warning: 66 : BindingExpression (hash=2902278): Resolving source
System.Windows.Data Warning: 69 : BindingExpression (hash=2902278): Found data context element: TextBlock (hash=18876224) (OK)
System.Windows.Data Warning: 70 : BindingExpression (hash=2902278): DataContext is null
System.Windows.Data Warning: 66 : BindingExpression (hash=2902278): Resolving source  (last chance)
System.Windows.Data Warning: 69 : BindingExpression (hash=2902278): Found data context element: TextBlock (hash=18876224) (OK)
System.Windows.Data Warning: 77 : BindingExpression (hash=2902278): Activate with root item <null>
System.Windows.Data Warning: 105 : BindingExpression (hash=2902278):   Item at level 0 is null - no accessor
System.Windows.Data Warning: 79 : BindingExpression (hash=2902278): TransferValue - got raw value {DependencyProperty.UnsetValue}
System.Windows.Data Warning: 87 : BindingExpression (hash=2902278): TransferValue - using fallback/default value ''
System.Windows.Data Warning: 88 : BindingExpression (hash=2902278): TransferValue - using final value ''

En parcourant la liste, vous pouvez en réalité voir l’entièreté du processus que WPF traverse pour essayer de trouver une valeur correcte pour votre contrôle TextBlock. À plusieurs reprises vous pouvez voir qu'il a été incapable de trouver un DataContext correct, et finalement il utilise la valeur par défaut {DependencyProperty.UnsetValue} qui se traduit par une chaine de caractères vide.

Utilisation du vrai débogueur

L'astuce ci-dessus peut être très bien pour diagnostiquer un mauvais binding mais dans certains cas, il est plus simple et plus plaisant de travailler avec le vrai débogueur. Les bindings ne supportent pas nativement cette fonctionnalité étant donné qu'ils sont gérés profondément en interne de WPF. Mais en utilisant un Converter, comme nous l'avons vu dans un article précédent, vous pouvez sautez à l'intérieur de ce processus et le parcourir étape par étape. Vous n'avez pas réellement besoin d'un convertisseur faisant quoique ce soit d'utile, vous avez juste besoin d'un moyen d'atteindre l'intérieur du processus de binding, et un convertisseur bidon vous y mènera :

<Window x:Class="WpfTutorialSamples.DataBinding.DataBindingDebuggingSample"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:self="clr-namespace:WpfTutorialSamples.DataBinding"
        Title="DataBindingDebuggingSample" Name="wnd" Height="100" Width="200">
	<Window.Resources>
		<self:DebugDummyConverter x:Key="DebugDummyConverter" />
	</Window.Resources>
    <Grid Margin="10">
		<TextBlock Text="{Binding Title, ElementName=wnd, Converter={StaticResource DebugDummyConverter}}" />
	</Grid>
</Window>
using System;
using System.Windows;
using System.Windows.Data;
using System.Diagnostics;

namespace WpfTutorialSamples.DataBinding
{
	public partial class DataBindingDebuggingSample : Window
	{
		public DataBindingDebuggingSample()
		{
			InitializeComponent();
		}
	}

	public class DebugDummyConverter : IValueConverter
	{
		public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
		{
			Debugger.Break();
			return value;
		}

		public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
		{
			Debugger.Break();
			return value;
		}
	}
}

Dans le fichier de Code-behing, nous définissons un DebugDummyConverter. Dans les méthodes Convert() et ConvertBack(), nous appelons Debugger.Break() qui a le même effet que de placer un point d'arrêt (breakpoint) dans Visual Studio. Et ensuite nous retournons la valeur fournie en entrée sans y toucher.

Dans le XAML, nous ajoutons une référence à notre convertisseur dans les ressources de la fenêtre et nous l'utilisons ensuite dans notre binding. Dans une vraie application, vous devriez plutôt définir le convertisseur dans un fichier à part et ensuite ajouter la référence dans App.xaml de manière à pouvoir l'utiliser partout dans l'application sans avoir à créer une nouvelle référence pour chaque fenêtre. Mais pour cet exemple, le code ci-dessus fera l'affaire.

Si vous exécuter l'exemple, vous verrez que le débogueur s'arrête dès que WPF essayer de récupérer la valeur pour le titre de la fenêtre. Vous pouvez maintenant examiner les valeurs passé à la méthode Convert() ou même les modifier avant de continuer l'exécution en utilisant les fonctionnalités offertes par le débogueur de Visual Studio.

Si le débogueur ne s'interrompt jamais, cela signifie que le convertisseur n'est pas utilisé. En général, cela indique l'expression de votre binding est incorrecte, ce que vous pouvez diagnostiquer et corriger en utilisant les méthodes décrites au début de cet article. L'astuce du convertisseur bidon est valable uniquement pour tester des expressions de binding valides.


This article has been fully translated into the following languages: Is your preferred language not on the list? Click here to help us translate this article into your language!