Accueil

Debugger un binding WPF

by Jean-Camille Mercier 23. mai 2013 17:29

Je me sers de deux méthodes pour débuggger un binding :

  1. Le DebugConverter avec un Path="."
  2. La trace dans l'Output
Dans 95% des cas, la technique du DebugConverter permet de résoudre le problème. Ce converter astucieux va simplement vous donner la main sur un point d'arret.
public class DebugConverter : IValueConverter
{
    public object Convert(object value, Type targetType, 
                      object parameter, CultureInfo culture)
    {
        Debugger.Break();
        return value;
    }

    public object ConvertBack(object value, Type targetType, 
                      object parameter, CultureInfo culture)
    {
        Debugger.Break();
        return value;
    }
}
Il suffi donc de l'utiliser avec un Path="." pour savoir exactement sur quoi on est bindé et ajuster si besoin :
<TextBlock Text="{Binding ., Converter={StaticResource DebugConverter}}" />
 
 
Par contre il peut arriver que le DebugConverter ne soit même pas appelé, par exemple lorsque votre binding attaque une RelativeSource qui n'est pas résolu. Dans ce cas, il faut monter le niveau de trace avec PresentationTraceSources.TraceLevel pour voir toute la mécanique du binding dans l'Output :
xmlns:diagnostics="clr-namespace:System.Diagnostics;assembly=WindowsBase"

Visibility="{Binding PeutModifier, 
    Converter={StaticResource BoolVisibleCollapsedConverter},
    RelativeSource={RelativeSource 
          Mode=FindAncestor, 
          AncestorType={x:Type oCtrl:LesionsModif}}, 
    diagnostics:PresentationTraceSources.TraceLevel=High, 
    FallbackValue=bug?}"
Vous verrez donc apparaître ce genre de trace :
Created BindingExpression (hash=12171805) for Binding (hash=12200949)
  Path: 'PeutModifier'
BindingExpression (hash=12171805): Default mode resolved to OneWay
BindingExpression (hash=12171805): Default update trigger resolved to PropertyChanged
BindingExpression (hash=12171805): Attach to Telerik.Windows.Controls.RadButton.Visibility (hash=61470144)
BindingExpression (hash=12171805): RelativeSource (FindAncestor) requires tree context
BindingExpression (hash=12171805): Resolve source deferred
BindingExpression (hash=12171805): Resolving source 
BindingExpression (hash=12171805): Found data context element: <null> (OK)
    Lookup ancestor of type MainWindow:  queried ContentPresenter (hash=17221593)
    Lookup ancestor of type MainWindow:  queried ContentControl (hash=36774220)
    Lookup ancestor of type MainWindow:  queried Grid (hash=44227181)
    ...
    Lookup ancestor of type MainWindow:  queried ItemsPresenter (hash=65918887)
    Lookup ancestor of type MainWindow:  queried AdornerDecorator (hash=48036196)
    Lookup ancestor of type MainWindow:  queried Border (hash=14145200)
    Lookup ancestor of type MainWindow:  queried MainWindow (hash=32554230)
  RelativeSource.FindAncestor found MainWindow (hash=32554230)
BindingExpression (hash=12171805): Activate with root item MainWindow (hash=32554230)
BindingExpression (hash=12171805):   At level 0 - for MainWindow.PeutModifier found accessor RuntimePropertyInfo(PeutModifier)
BindingExpression (hash=12171805): Replace item at level 0 with MainWindow (hash=32554230), using accessor RuntimePropertyInfo(PeutModifier)
BindingExpression (hash=12171805): GetValue at level 0 from MainWindow (hash=32554230) using RuntimePropertyInfo(PeutModifier): 'False'
BindingExpression (hash=12171805): TransferValue - got raw value 'False'
BindingExpression (hash=12171805): TransferValue - user's converter produced 'Collapsed'
BindingExpression (hash=12171805): TransferValue - using final value 'Collapsed'


.
Il y a plein d'infos intéressantes : le sens du binding, le déclencheur (ce n'est pas toujours le même par défaut), les deux path, la résolution de la source avec sa trace complète, l'état du binding et même tous les changements d'état !!
 
A vous ensuite de trouver la faille !