Time Picker User Control
The easiest way to create a WPF TimePicker control is to make a user control wrapped for TimeSpan CLR object. Here is a very simple sample which does that. Basically TimeControl is having 4 DPs one for the entire Value (Which is a TimeSpan) and individual Hours, Minutes and Seconds. (We can optionally add Days and Milliseconds also to make the control rich).
Here is a C# class TimeControl.xaml.cs public partial class TimeControl : UserControl
{
public TimeControl()
{
InitializeComponent();
}
public TimeSpan Value
{
get { return (TimeSpan)GetValue(ValueProperty); }
set { SetValue(ValueProperty, value); }
}
public static readonly DependencyProperty ValueProperty =
DependencyProperty.Register("Value", typeof(TimeSpan), typeof(TimeControl),
new UIPropertyMetadata(DateTime.Now.TimeOfDay, new PropertyChangedCallback(OnValueChanged)));
private static void OnValueChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
TimeControl control = obj as TimeControl;
control.Hours = ((TimeSpan)e.NewValue).Hours;
control.Minutes = ((TimeSpan)e.NewValue).Minutes;
control.Seconds = ((TimeSpan)e.NewValue).Seconds;
}
public int Hours
{
get { return (int)GetValue(HoursProperty); }
set { SetValue(HoursProperty, value); }
}
public static readonly DependencyProperty HoursProperty =
DependencyProperty.Register("Hours", typeof(int), typeof(TimeControl),
new UIPropertyMetadata(0, new PropertyChangedCallback(OnTimeChanged)));
public int Minutes
{
get { return (int)GetValue(MinutesProperty); }
set { SetValue(MinutesProperty, value); }
}
public static readonly DependencyProperty MinutesProperty =
DependencyProperty.Register("Minutes", typeof(int), typeof(TimeControl),
new UIPropertyMetadata(0, new PropertyChangedCallback(OnTimeChanged)));
public int Seconds
{
get { return (int)GetValue(SecondsProperty); }
set { SetValue(SecondsProperty, value); }
}
public static readonly DependencyProperty SecondsProperty =
DependencyProperty.Register("Seconds", typeof(int), typeof(TimeControl),
new UIPropertyMetadata(0, new PropertyChangedCallback(OnTimeChanged)));
private static void OnTimeChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
TimeControl control = obj as TimeControl;
control.Value = new TimeSpan(control.Hours, control.Minutes, control.Seconds);
}
private void Down(object sender, KeyEventArgs args)
{
switch (((Grid)sender).Name)
{
case "sec":
if (args.Key == Key.Up)
this.Seconds++;
if (args.Key == Key.Down)
this.Seconds--;
break;
case "min":
if (args.Key == Key.Up)
this.Minutes++;
if (args.Key == Key.Down)
this.Minutes--;
break;
case "hour":
if (args.Key == Key.Up)
this.Hours++;
if (args.Key == Key.Down)
this.Hours--;
break;
}
}
}
<UserControl
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="DateTimeTest.TimeControl"
Height="Auto" Width="Auto" x:Name="UserControl">
<Grid x:Name="LayoutRoot" Width="Auto" Height="Auto">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.2*"/>
<ColumnDefinition Width="0.05*"/>
<ColumnDefinition Width="0.2*"/>
<ColumnDefinition Width="0.05*"/>
<ColumnDefinition Width="0.2*"/>
</Grid.ColumnDefinitions>
<Grid x:Name="hour" Focusable="True" KeyDown="Down">
<TextBlock x:Name="mmTxt" TextWrapping="Wrap" Text="{Binding Path=Hours, ElementName=UserControl, Mode=Default}"
TextAlignment="Center" VerticalAlignment="Center" FontFamily="Goudy Stout" FontSize="14"/>
</Grid>
<Grid Grid.Column="1">
<TextBlock x:Name="sep1" TextWrapping="Wrap" VerticalAlignment="Center" Background="{x:Null}" FontFamily="Goudy Stout"
FontSize="14" Text=":" TextAlignment="Center"/>
</Grid>
<Grid Grid.Column="2" x:Name="min" Focusable="True" KeyDown="Down">
<TextBlock x:Name="ddTxt" TextWrapping="Wrap" Text="{Binding Path=Minutes, ElementName=UserControl, Mode=Default}"
TextAlignment="Center" VerticalAlignment="Center" FontFamily="Goudy Stout" FontSize="14"/>
</Grid>
<Grid Grid.Column="3">
<TextBlock x:Name="sep2" TextWrapping="Wrap" VerticalAlignment="Center" Background="{x:Null}" FontFamily="Goudy Stout"
FontSize="14" Text=":" TextAlignment="Center"/>
</Grid>
<Grid Grid.Column="4" Name="sec" Focusable="True" KeyDown="Down">
<TextBlock x:Name="yyTxt" TextWrapping="Wrap" Text="{Binding Path=Seconds, ElementName=UserControl, Mode=Default}"
TextAlignment="Center" VerticalAlignment="Center" FontFamily="Goudy Stout" FontSize="14"/>
</Grid>
</Grid>
</UserControl>
And the control can be used as
<ctrl:TimeControl Hours="10" Minutes="10" Seconds="30" x:Name="TimeControl"/>
Comments
I also created a time picker. Have a look at it and give me your feedback..
http://marlongrech.wordpress.com/2007/11/18/time-picker/
Thanks
It still throws an exception at over 59 minutes, and under -59 minutes. I'm not sure if that was in the scope of what you did here though.
Hope this helps someone! :)
It still throws an exception at over 59 minutes, and under -59 minutes. I'm not sure if that was in the scope of what you did here though.
Hope this helps someone! :)
I used it after modifying it ,
to control range I added MouseWheel event in each textbox , please note that I renamed the Textboxs also for hh,mm,ss
private void hhTxt_MouseWheel_1(object sender, MouseWheelEventArgs e)
{
scroll(sender, e, 23);
}
private void mmTxt_MouseWheel_1(object sender, MouseWheelEventArgs e)
{
scroll(sender, e, 59);
}
private void ssTxt_MouseWheel_1(object sender, MouseWheelEventArgs e)
{
scroll(sender, e, 59);
}
private void scroll(object sender, MouseWheelEventArgs e, int maxVal = 59)
{
var v = int.Parse(((TextBox)sender).Text);
if( e.Delta<0)
if (v == 0) v = maxVal ; else v = v - 1;
else
if (v == maxVal ) v = 00; else v = v + 1;
var s = v.ToString("00");
((TextBox)sender).Text = s;
((TextBox)sender).Select(0, 2);
}