Technology Experience
.NET World

Silverlight, controllo DatePicker e formattazione customizzata (con problemi di focus)

Mi sono scontrato con questo problema qualche giorno fa, ma trovo il tempo e la voglia di parlarne solo questa sera. Dunque, il tutto gira attorno a Silverlight ed al controllo DatePicker, dichiarato nel namespace System.Windows.Controls. La cosa interessante di questo controllo è che in tempi rapidi possiamo ottenere una view Silverlight come questa:

DatePicker01

che corrisponde più o meno alla seguente porzione di XAML:

<TextBox Grid.Row="0" Grid.Column="1" Height="26" />
<TextBox Grid.Row="1" Grid.Column="1" Height="26" />
<ctl:DatePicker Grid.Row="2" Grid.Column="1" Height="26" />
<TextBox Grid.Row="3" Grid.Column="1" Height="26" />

 

Tanto per chiarirci: la vista è una Grid, divisa in 2 colonne e 4 righe. Lo XAML qui sopra rappresenta il contenuto della colonna di destra, in pratica i 4 controlli di input: 3 TextBox per l’inserimento di cognome, nome e note, ed un DatePicker per l’inserimento della data di nascita. Nell’immagine qui sopra il DatePicker è evidenziato nel rettangolo verde.

Il controllo DatePicker è splendido e funziona bene, ma ha un piccolo difetto: non è possibile personalizzare il formato della data. Il controllo infatti dispone di una proprietà SelectedDateFormat, che però può valere solo Short o Long. Non potete specificare una string format customizzata, e quindi o vi vanno bene le due previste, oppure siete fregati. C’è una soluzione? Diciamo che googlando si trova un barbatrucco.

Questo barbatrucco consiste nell’usare due controlli separati invece di uno solo: più precisamente, una TextBox ed ancora il nostro DatePicker:

<TextBox Grid.Row="0" Grid.Column="1" Height="26" />
<TextBox Grid.Row="1" Grid.Column="1" Height="26" />
<toolkit:DockPanel Grid.Row="2" Grid.Column="1" LastChildFill="True">
    <ctl:DatePicker toolkit:DockPanel.Dock="Right" Width="23" />
    <TextBox toolkit:DockPanel.Dock="Left" Height="26" />
</toolkit:DockPanel>
<TextBox Grid.Row="3" Grid.Column="1" Height="26" />

 

Notate come è cambiata la terza riga. Ho usato un DockPanel (panel che adoro, onestamente) e dentro ho inserito i due controlli. Giocando con la proprietà LastChildFill=”True” faccio in modo che la TextBox riempia tutto lo spazio disponibile, mentre del DatePicker faccio comparire solamente il minimo indispensabile, ovvero il calendarietto che l’utente deve cliccare per scegliere la data. Ovviamente in un ambiente reale, realizzato con MVVM, la TextBox ed il DatePicker sarebbero bindate alla stessa proprietà, con il vantaggio però che nel binding di una normale TextBox posso specificare la stringa di formattazione che voglio. La UI appare come segue:

DatePicker02

Molto simile, praticamente nella UI non si vede alcuna differenza. Invece dal punto di vista della usability, una piccola differenza c’è. Se l’utente è abituato a navigare da un controllo all’altro premendo TAB, vedrà che c’è un piccolo problemuccio. La sequenza del TAB infatti è la seguente:

  1. TextBox del Cognome (come in figura)
  2. TextBox del Nome
  3. vuoto, boh, non si vede
  4. TextBox della Data di Nascita
  5. TextBox delle Note varie

Quel vuoto, boh, non si vede è ovviamente il DatePicker, che al momento opportuno si prende il focus. Piccola osservazione: graficamente questo focus non si vede, e soprattutto non c’è alcuna combinazione di tasti che fa apparire il calendario per scegliere la data, quindi sono obbligato ad usare il mouse. La conclusione di tutto ciò è la seguente: per passare dal Nome alla Data di Nascita l’utente deve premere due volte TAB, il che non va molto bene. Un utente evoluto magari capisce al volo, ma un altro magari no, e nonostante questo, diciamolo pure: è proprio brutto.

Come si risolve questa cosa? Beh, il DatePicker è un Control, quindi…direte voi…basta impostare IsTabStop=”False” sul controllo ed il gioco è fatto.

Falso.

Anche mettendo IsTabStop=”False” il DatePicker si prende il focus esattamente come prima. E quindi? Quindi vuol dire che qualcosa dentro il controllo ruba comunque il focus, anche se noi gli abbiamo detto di no. E quindi bisogna usare le armi pesanti, ovvero lavorare sul template interno del controllo.

Come fare? Seguite i semplici passi (cercherò di essere breve):

  1. Aprite Expression Blend 4.0
  2. Cominciate un nuovo progetto di tipo Silverlight 4.0
  3. Aggiungete alla MainPage un controllo DatePicker, avendo prima aggiunto nei riferimenti l’assembly

    C:Program Files (x86)Microsoft SDKsSilverlightv4.0LibrariesClientSystem.Windows.Controls.dll
  4. A questo punto cliccate con il destro sul controllo, andate su Edit Template e poi su Edit a Copy
  5. Assegnate pure un nome alla nuova risorsa Style che Blend sta per creare
  6. Passate alla vista XAML, copiate lo style DatePickerStyle1 ed incollate dentro Visual Studio 2010

Lo stile è come al solito piuttosto complesso, perchè contiene TUTTO ciò che serve al runtime di Silverlight per disegnare il controllo. Quindi avete colori, altri controlli, animazioni, effetti, etc. etc. Vi aiuterò e vi semplificherò la vista: con un pezzettino di altro codice (che vi risparmio) sono riuscito a capire qual’è il controllo che ruba il focus. Ed è esattemente il seguente:

<System_Windows_Controls_Primitives:DatePickerTextBox
    x:Name="TextBox"
    BorderBrush="{TemplateBinding BorderBrush}"
    BorderThickness="{TemplateBinding BorderThickness}"
    Background="{TemplateBinding Background}"
    Grid.Column="0"
    Padding="{TemplateBinding Padding}"
    SelectionBackground="{TemplateBinding SelectionBackground}"/>

 

Questo è il controllo maledetto che ruba il focus. E’ sufficiente mettere qui IsTabStop=”True” per risolvere tutti i vostri problemi. Fatto questo, il TAB funziona regolarmente, saltate da un controllo all’altro senza che nessuno vi rubi il focus, potete formattare le date come volete voi, etc. etc.

Alla prossima.

Send to Kindle

Igor Damiani

La sua passione per l'informatica nasce nella prima metà degli anni '80, quando suo padre acquistò un Texas Instruments TI-99. Da allora ha continuato a seguire l'evoluzione sia hardware che software avvenuta nel corso degli anni. E' un utente, un videogiocatore ed uno sviluppatore software a tempo pieno. Igor ha lavorato e lavora anche oggi con le più moderne tecnologie Microsoft per lo sviluppo di applicazioni: .NET Framework, XAML, Universal Windows Platform, su diverse piattaforme, tra cui spiccano Windows 10 piattaforme mobile. Numerose sono le app che Igor ha creato e pubblicato sul marketplace sotto il nome VivendoByte, suo personale marchio di fabbrica. Adora mantenere i contatti attraverso Twitter e soprattutto attraverso gli eventi delle community .NET.

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *

Questo sito usa Akismet per ridurre lo spam. Scopri come i tuoi dati vengono elaborati.