Qualche giorno fa sul forum WPF di Microsoft Italia, è stata fatta una domanda da parte di uno sviluppatore che aveva la necessità di acquisire sia una data che un ora e voleva farlo su due controlli distinti.
I controlli standard WPF comprendono solo il controllo DateTime, che non permette di avere dei formati che diano modo di acquisire solo la data o solo l’ora.
E’ abbastanza primitivo da essere adatto solo a permettere l’acquisizizone utilizzando il calendario. Una acquisizione piuttosto lenta e priva del valore dell’ora.
Ricordandomi di aver usato, all’inizio dei miei test con WPF il WPF Toolkit Extended di Microsoft, che si trovava su Codeplex, e che in questo toolkit c’erano una serie di controlli più sofisticati di quelli di base, sono andata a cercarlo per vedere se fosse possibile risolvere il problema.
Il WPF toolkit Extended originale, che ho ancora fra le mie librerie non esiste più su codeplex, ma è stato ereditato, modificato ed è ancora portato avanti (l’ultima release è del 3/5/2016) da un azienda (o un gruppo) che si chiama XCeed che ne ha sviluppato una versione professional con molte cose in più che può essere acquistata ma che sviluppa e mantiene ancora oggi una versione Community che è gratuita e può essere scaricata qui: https://wpftoolkit.codeplex.com/
Scaricata l’ultima versione, ho verificato come referenziarla e ho creato un piccolo esempio:
In questo programma WPF, Ho referenziato la libreria Xceed.Wpf.Toolkit.dll ed ho modificato nel modo seguente MainWindow.xaml
<Window x:Class="DateAndTimePickers.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:xtkc="clr-namespace:Xceed.Wpf.Toolkit;assembly=Xceed.Wpf.Toolkit" xmlns:local="clr-namespace:DateAndTimePickers" mc:Ignorable="d" Title="My Date And Time Pickers" Height="140" Width="300"> </Window>
Le modifiche alla Window riguardano l’inclusione del namespace necessario ad usare i controlli date time picker, il titolo e le dimensioni della Window.
<Grid> <Grid.BindingGroup> <BindingGroup/> </Grid.BindingGroup> <Grid.RowDefinitions> <RowDefinition Height="50*"/> <RowDefinition Height="50*"/> <RowDefinition Height="Auto"/> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition Width="50*"/> <ColumnDefinition Width="50*"/> </Grid.ColumnDefinitions> <StackPanel Grid.Row="2" Grid.ColumnSpan="2" Orientation="Horizontal" FlowDirection="RightToLeft"> <Button Content="Show Date and time" Padding="10,4,10,4" Margin="4,2,4,2" Click="ShowDateTime_Click"/> </StackPanel> <Label Grid.Row="0" Grid.Column="0" HorizontalAlignment="Right" VerticalAlignment="Center" Margin="4,10,4,2" Content="Insert Date" /> <xtkc:DateTimePicker Grid.Row="0" Grid.Column="1" HorizontalAlignment="Left" VerticalAlignment="Center" Margin="4,10,4,2" Width="120" Value="{Binding MyDateTime, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Format="ShortDate" /> <Label Grid.Row="1" Grid.Column="0" HorizontalAlignment="Right" VerticalAlignment="Center" Margin="4,2,4,2" Content="Insert Time" /> <xtkc:DateTimeUpDown Grid.Row="1" Grid.Column="1" HorizontalAlignment="Left" VerticalAlignment="Center" Margin="4,2,4,2" Width="120" Value="{Binding MyDateTime, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Format="LongTime" /> </Grid>
Nella grid fornita dalla Window Standard, ho inserito uno StackPanel orizzontale con un Button per testare il valore della variabile in binding, ed ho inserito 2 Label, un DateTimePicker ed un DateTimeUpDown.
Entrambi i controlli data, sono in Binding alla stessa variabile chiamata MyDateTime.
Vediamo ora il codice C# di MainWindow.cs
public MainWindow() { InitializeComponent(); this.DataContext = this; }
Nel costruttore faccio divenire la finestra ViewModel di se stessa.
public const string FLD_MyDateTime = "MyDateTime";
public DateTime MyDateTime { get { return (DateTime)this.GetValue(MyDateTimeProperty); } set { this.SetValue(MyDateTimeProperty, value); } } public static readonly DependencyProperty MyDateTimeProperty = DependencyProperty.Register( FLD_MyDateTime, typeof(DateTime), typeof(MainWindow), new FrameworkPropertyMetadata(DateTime.Now, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
Definisco una dependency property, per il campo in binding, attenzione, non è strettamente indispensabile che sia una dependency property, può anche essere una normale property ma la classe deve implementare INotifyPropertyChanged e la property deve scatenare OnPropertyChanged quando viene modificata. (L’uso della costante per il nome della variabile è uno dei miei pattern personali, non è indispensabile, io lo uso per ricordarmi che se rinomino una property devo ricordarmi di modificare tutte le dichiarazioni.
private void ShowDateTime_Click(object sender, RoutedEventArgs e) { MessageBox.Show(string.Format("Ho inserito: {0} {1}", MyDateTime.ToShortDateString(), MyDateTime.ToLongTimeString())); }
Il codice del Button Click mostra il valore della property, in modo da testare se la modifica alla property funziona.
Provando a impostare data e ora e cliccando il bottone vediamo come entrambi i dati sono visualizzati
Modificando solo l’ora, vediamo che la data viene conservata.
Potete scaricare il progetto esempio dal link qui indicato:
Per qualsiasi domanda, approfondimento, commento, o per segnalare un errore potete usare il link al modulo di contatto in cima alla pagina.