Leggendo per caso il blog di Gianni Giaccaglini (http://blogs.wpfitalia.it/GianniGiaccaglini/archive/2011/09/08/Binding-ADO-tramite-classe-ad-hoc.aspx) riguardo il binding verso dataset, ho notato un capitolo, “INotifyPropertyChanged server davvero?” e mi sono ricordato di un problema simile (forse lo stesso) che mi è capitato tempo fa.
Iniziamo dal codice xaml e il datacontext:
<StackPanel>
<TextBox Text="{Binding Path=PrimaProp}" />
<TextBox Text="{Binding Path=PrimaProp}" />
<TextBox Text="{Binding Path=SecondaProp}" />
<TextBox Text="{Binding Path=SecondaProp}" />
<Button Content="Cambia" Click="Button_Click" />
</StackPanel>
public class MyDataContext
{
public string PrimaProp { get; set; }
public string SecondaProp { get; set; }
}
Qualcuno noterà che MyDataContext (nel codebehind viene impostata un istanza come DataContext) non implementa INotifyPropertyChanged.
Modificando una textbox ci si aspetterebbe che le altre non cambino perchè non si notifica alla vista che la proprietà è stata cambiata… E invece tutto funziona!
Ai tempi pensai che l’engine di wpf fosse abbastanza intelligente da usare un oggetto binding uguale se viene scritto uguale in più parti… invece no .
Se proviamo infatti a impostare via codice il binding (es: textbox1.SetBinding(TextBox.TextProperty, new Binding(“PrimaProp”))), con nuove istanze di Binding su diversi oggetti, continua ancora a funzionare.
Proviamo a cambiare la proprietà del datacontext da codice tramite il bottone con:
(this.DataContext as MyDataContext).SecondaProp=”modifica da codice”… NON FUNZIONA!
Non sapendo dove andare a parare, ho cercato con google, e infine ho trovato la soluzione indicata qui: http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/9365bb6a-b411-4967-9a03-ae2a810fb215/
Sunto della soluzione:
– Se un oggetto CLR implementa INotifyPropertyChanged, è cura del developer lanciare l’evento NotifyPropertyChanged
– Se un oggetto CLR NON implementa INotifyPropertyChanged, il binding lavora sul TypeDescriptor dell’oggetto. Esso va a registrare alla modifica delle proprietà tramite PropertyDescriptor.AddValueChanged().
Quindi:
1) come far andare il codice precedente riguardo il bottone:
”semplice” (?!?) basta recuperare la PropertyDescriptor dell’oggetto e impostare così la proprietà:
var propertyDescriptor = TypeDescriptor.GetProperties(this.DataContext).Find(“SecondaProp”, false);
propertyDescriptor.SetValue(this.DataContext, “ModificaDaCodice”);
2) come far smettere di andare il precedente esempio:
Implementiamo l’interfaccia INotifyPropertyChanged e propaghiamo l’evento solo per PrimaProp. Questa funziona, ma SecondaProp no .
Performance (mentre l’ho fatto ho sentito l’esigenza di un altro post)
Se eseguo il codice nel thread UI, le performance sono molto simili.
Se eseguo il codice in un altro thread, l’utilizzo di INotifyPropertyChanged risulta più rapido rispetto a PropertyDescriptor.
Conclusioni:
Data la flessibilità e la maggior facilità implementativa, la mia preferenza ricade indubbiamente a INotifyPropertyChanged. Le performance inoltre sembrerebbero avvalorare tale scelta. Quindi Me.NofifyPropertyChanged(“you”);