Spesso mi sento porre la domanda: “ma in un’applicazione MVVM con WPF, come faccio il debug del databinding?”. Ebbene sì, è una domanda intelligente. Mano a mano che portiamo le nostre applicazioni client in architettura MVVM, ci rendiamo conto che dipendiamo sempre più pesantemente dal buon funzionamento del databinding, vero e proprio fulcro del pattern MVVM.
Sia chiaro, il databinding di WPF funziona a meraviglia… quello che potrebbe non funzionare sono le binding expression che utilizziamo nelle nostre applicazioni. Vediamo un pò se riusciamo ad utilizzare una tecnica per effettuare un debug del databinding in modo piuttosto semplice.
Il problema
Il problema con il databinding di WPF è che è un pò troppo “permissivo” e in alcuni casi “oscuro”. Mi spiego meglio: se utilizzo una binding expression errata, ovvero che fa riferimento ad una proprietà che non esiste, o che magari ho rinominato, l’errore non “salta all’occhio”, ovvero non viene lanciata un’eccezione visibile. Questa situazione è spesso facilmente risolvibile inserendo un breakpoint sulla proprietà del ViewModel bindato al controllo, ma nel caso di binding “element-to-element” il debugging può diventare veramente complicato. Ricordiamo infatti che nello xaml non è possibile inserire breakpoints.
La soluzione
La soluzione che si può impiegare nei casi di problemi di databinding è rappresentata dall’utilizzo di un Converter neutro, ovvero un convertitore che di fatto non converte, ma viene solamente utilizzato per scopi di debug. Questo può essere utilizzato nelle proprietà “databindate” e in esso è possibile fissare breakpoints o implementare un logging del databinding. E’ inoltre possibile accorgersi di quali binding non vengono utilizzati, in quanto il codice in quei casi non passa per i breakpoints. Vediamo un pò di codice:
1: <Window x:Class="DatabindingDebug.Views.MainView"
2: xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
3: xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
4: xmlns:c="clr-namespace:DatabindingDebug.Commands"
5: xmlns:local="clr-namespace:DatabindingDebug.Converters"
6: Title="Main Window" Height="400" Width="400">
7:
8: <Window.Resources>
9: <local:NeutralConverter x:Key="NeutralConverter" />
10: </Window.Resources>
11:
12: <Grid>
13: <Grid.RowDefinitions>
14: <RowDefinition Height="40" />
15: <RowDefinition Height="40" />
16: <RowDefinition Height="40" />
17: <RowDefinition Height="40" />
18: </Grid.RowDefinitions>
19: <TextBox Grid.Row="0" Margin="4,4,4,4" Text="{Binding Path=Name, Converter={StaticResource NeutralConverter}}"/>
20: <TextBox Grid.Row="1" Margin="4,4,4,4" Text="{Binding Path=LastName, Converter={StaticResource NeutralConverter}}"/>
21: <Slider Grid.Row="2" Margin="4,4,4,4" x:Name="sldValue"/>
22: <TextBox Grid.Row="3" Margin="4,4,4,4" Text="{Binding ElementName=sldValue, Path=Value, Converter={StaticResource NeutralConverter}}"/>
23: </Grid>
24: </Window>
Nella view si può vedere come il converter NeutralConverter sia applicato alle proprietà che si vogliono controllare. La prima textbox è collegata di proposito ad una proprietà che nel ViewModel non esiste. Se provate a lanciare l’applicazione, questa non darà nessun errore, ma nella finestra di output verrà notificato un System.Windows.Data Error, e precisamente un Binding Expression Path Error. Ovviamente il codice non passerà per il breakpoint fissato nel converter. Vediamo il codice del converter:
1: namespace DatabindingDebug.Converters
2: {
3: using System;
4: using System.Globalization;
5: using System.Windows.Data;
6:
7: class NeutralConverter : IValueConverter
8: {
9: #region IValueConverter Members
10:
11: public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
12: {
13: //System.Diagnostics.Debug.WriteLine(value);
14: return value;
15: }
16:
17: public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
18: {
19: return value;
20: }
21:
22: #endregion
23: }
24: }
Il codice del converter è veramente banale, ma potrebbe essere esteso per implementare un logging per controllare il databinding nei casi più complessi. La riga commentata può essere utilizzata per loggare i valori in binding.
Non riporto il codice del ViewModel, in quanto sono presenti solo due proprietà FirstName e LastName che sono messe in binding con le due textbox della view.
Conclusioni
Questo trucchetto può essere utile nei casi disperati, ovvero quando non riusciamo a capire se un certo valore viene collegato ad un controllo correttamente o quando si effettua il databinding element-to-element, che è tanto utile quanto “pericoloso”, in quanto si impiega uno strato di WPF fuori dal nostro controllo, che non è facilmente debuggabile.