Usare un DateTimeConverter nei progetti WPF
Eventuali imprecisioni sono dovute all’ascolto, durante la stesura del post, di un concerto del Liga.
Chiedo scusa: aiutatemi con i vostri commenti. 🙂
La classe DateTimeConverter è definita nel namespace System.ComponentModel nell’assembly System.dll. Il primo pensiero che ho avuto quando ho scoperto la presenza di questa classe – con questo nome – è stato: cavolo, posso metterla nelle risorse di una Window e sfruttarla nel meccanismo di data-binding tra un tipo DateTime ed un semplice controllo come la TextBox.
Supponiamo di avere una Window semplice definita così:
1 <Window x:Class="StudyWPF.DataBindingWindow" 2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 4 xmlns:cnv="clr-namespace:System.ComponentModel;assembly=System" 5 Title="StudyWPF" Height="300" Width="300"> 6 <Window.Resources> 7 <cnv:DateTimeConverter x:Key="cnvDateTime" /> 8 </Window.Resources> 9 </Window>
Ho aggiunto un riferimento al namespace System.ComponentModel dentro l’assembly System.dll con i metodi di cui abbiamo parlato più o meno tutti in passato. Due note. Primo: occhio, la “a” di “assembly” alla riga (4) nel mapping del namespace deve essere obbligatoriamente minuscola. Secondo: il riferimento all’assembly, sempre alla riga (4) non deve avere estensione. Ogni volta ci perso mezz’ora, spero che scrivendolo questo tempo diminuisca. 🙂
Fatto questo, ho definito fra le risorse un’istanza di DateTimeConverter, usando come key la stringa “cnvDateTime”. Se provate a compilare, non avrete alcun errore. L’istanza del converter viene creata. Ma se provate ad usarla in un qualche data-binding, fallirà. Ve lo dimostro, sperando di non dire qualche stupidaggine (in tal caso, leggere il prologo all’inizio). Guardate il seguente XAML:
<Window x:Class="StudyWPF.DataBindingWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:StudyWPF" xmlns:cnv="clr-namespace:System.ComponentModel;assembly=System" Title="StudyWPF" Height="300" Width="300" DataContext="{DynamicResource player}"> <Window.Resources> <s:HockeyPlayer x:Key="player" /> <cnv:DateTimeConverter x:Key="cnvDateTime" /> </Window.Resources> <TextBox Text="{Binding Path=Data}" /> </Window>
E’ una sorta di evoluzione di quello di prima. Fra le risorse c’è ancora il DateTimeConverter di prima. Ho aggiunto un nuovo namespace ed una nuova risorsa, per avere a disposizione un oggetto di business che mi vada ad esporre una proprietà pubblica di tipo DateTime. Tale oggetto è uno HockeyPlayer (ve lo ricordate?) e mi espone una semplice proprietà Data. Ho impostato il DataContext della Window sulla risorsa player. In questo modo alla Window posso aggiungere una TextBox bindata all’oggetto secondo il Path=Data. Cosa mostra la TextBox? E’ presto detto…
Ovvero…una semplice ToString() sull’oggetto definita nella risorsa, che giustamente ha i valori di default per un’istanza di DateTime. Supponiamo adesso di voler sfruttare il converter: modifichiamo la definizione del data-binding sulla TextBox:
<TextBox Margin="4" Text="{Binding Path=Data, Converter={StaticResource cnvDateTime}}" />
Al data-binding ho detto di usare un converter, e nello specifico quello definito dalla risorsa. Il codice non compila: il messaggio di errore è:
Cannot convert the value in attribute ‘Converter’ to object of type ‘System.Windows.Data.IValueConverter’. Object of type ‘System.ComponentModel.DateTimeConverter’ cannot be converted to type ‘System.Windows.Data.IValueConverter’. Error at object ‘System.Windows.Data.Binding’ in markup file ‘StudyWPF;component/databindingwindow.xaml’ Line 15 Position 23.
Il messaggio è chiaro. WPF si aspetta converter che implementino l’interfaccia IValueConverter del namespace System.Windows.Data. La classe DateTimeConverter che abbiamo usato noi non fa nulla di tutto questo: grazie ad un giro con Reflector, vedo che deriva da TypeConverter, e non c’entra nulla.
Le soluzioni sono almeno due: o vi scrivete voi un DateTimeConverter adatto a funzionare con WPF (operazione semplicissima, al punto che è la strada che ho seguito), oppure date un’occhiata a questo progetto su CodeProject.com, che oltre al DateTimeConverter vi dà altri converter che potrebbero esservi utili in altri contesti.
Technorati Tags: .NET programming WPF