Get Microsoft Silverlight

Monday, October 29, 2007

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;
            }
        }
 
    } 



And here is the XAML for TimeControl.xaml





<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"/>

6 comments:

C# Disciple said...

Hi there,
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

Gimble said...

Thanks for this, but it seems that the beginning of the .cs file is missing :(

Brandon said...

I couldn't get this code to work for the life of me. Finally, after getting some help, I discovered that change the TextBlocks to TextBoxes (for focus issues maybe?) and the KeyDown to PreviewKeyDown, at least the numbers can be changed with the up/down keys!

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! :)

Brandon said...

I couldn't get this code to work for the life of me. Finally, after getting some help, I discovered that change the TextBlocks to TextBoxes (for focus issues maybe?) and the KeyDown to PreviewKeyDown, at least the numbers can be changed with the up/down keys!

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! :)

Sameh Mikhail said...

Thank you ,
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);
}

aparna john said...

Hi,Instead all you need is a good sense of design and an easy to use HTML editor in the likes of Dream Weaver and someone to guide you through the basics,On line there are many tutorials that assist you to design a good web page from scratch but the choice is very hard, as a matter of Web Design Cochin fact you probably don't even need one of those.Thanks.......