This project has moved and is read-only. For the latest updates, please go here.

WPF Toolkit Date time picker custom time interval

May 15, 2012 at 3:56 AM

How do you make the time interval 15 minutes rather than 1 hour?

i.e when they click to increase/decrease the time, it increases by a custom interval.

May 15, 2012 at 3:26 PM

Unfortunately, this feature is not supported.  To make it work, you will have to do some work on your end.  The DateTimePicker uses a TimePicker in the Popup that contains the calendar.  The TimePicker is a control that uses a DateTimeUpDown control to display and modify the time part.  The DateTimeUpDown increment and decrement the value by one unit on the targeted part (year, month, day, hour, minute, seconde, ...).  That part is either the first one available or the current selected one.

 

Right now, there is no property that allows you to alter the value to be incremented or decremented on the DateTimeUpDown control.  However, you may override the DateTimeUpDown.OnIncrement and DateTimeUpDown.OnDecrement methods to change the behavior.  For example, you may create a custom DateTimeUpDown like this:

public sealed class MyDateTimeUpDown : DateTimeUpDown
{
  protected override void OnIncrement()
  {
    this.AddValue( 15d );
  }

  protected override void OnDecrement()
  {
    this.AddValue( -15d );
  }

  private void AddValue( double value )
  {
    if( Value.HasValue )
    {
      Value = Value.Value.AddMinutes( value );
    }
    else
    {
      Value = DefaultValue;
    }
  }
}

The next step is to replace the template of the TimePicker that is located inside the DateTimePicker to make it use MyDateTimeUpDown instead of the regular DateTimeUpDown.  To do this, we'll put a style on the desired DateTimePicker.  That style will contain an implicit style for the TimePicker control.  The implicit style will assign a ControlTemplate to the Template property of the TimePicker.

 

<Window x:Class="Sample.DateTimePicker.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit"
        xmlns:conv="clr-namespace:Xceed.Wpf.Toolkit.Core.Converters;assembly=WPFToolkit.Extended"
        xmlns:local="clr-namespace:Sample.DateTimePicker"
        xmlns:chrome="clr-namespace:Xceed.Wpf.Toolkit.Chromes;assembly=WPFToolkit.Extended"
        Title="MainWindow" Height="350" Width="525">
   <Window.Resources>
      <Style x:Key="dateTimePickerStyle"
             TargetType="xctk:DateTimePicker">
         <Style.Resources>
            <conv:InverseBoolConverter x:Key="InverseBoolConverter" />
            <conv:TimeFormatToDateTimeFormatConverter x:Key="TimeFormatToDateTimeFormatConverter" />

            <LinearGradientBrush x:Key="PopupDarkBorderBrush" EndPoint="0.5,1" StartPoint="0.5,0">
               <GradientStop Color="#FFA3AEB9" Offset="0" />
               <GradientStop Color="#FF8399A9" Offset="0.375" />
               <GradientStop Color="#FF718597" Offset="0.375" />
               <GradientStop Color="#FF617584" Offset="1" />
            </LinearGradientBrush>

            <LinearGradientBrush x:Key="PopupBackgroundBrush" StartPoint="0,0" EndPoint="0,1">
               <LinearGradientBrush.GradientStops>
                  <GradientStopCollection>
                     <GradientStop Offset="0" Color="#FFffffff" />
                     <GradientStop Offset="1" Color="#FFE8EBED" />
                  </GradientStopCollection>
               </LinearGradientBrush.GradientStops>
            </LinearGradientBrush>

            <Style x:Key="TimePickerToggleButtonStyle" TargetType="ToggleButton">
               <Setter Property="Template">
                  <Setter.Value>
                     <ControlTemplate TargetType="ToggleButton">
                        <Grid SnapsToDevicePixels="True">
                           <chrome:ButtonChrome x:Name="ToggleButtonChrome"
                                       CornerRadius="0,2.75,2.75,0"
                                       RenderChecked="{Binding IsOpen, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=xctk:TimePicker}}"
                                       RenderEnabled="{Binding IsEnabled, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=xctk:TimePicker}}"
                                       RenderMouseOver="{TemplateBinding IsMouseOver}"
                                       RenderPressed="{TemplateBinding IsPressed}">

                              <Grid>
                                 <Grid.ColumnDefinitions>
                                    <ColumnDefinition Width="*" />
                                    <ColumnDefinition Width="Auto" />
                                 </Grid.ColumnDefinitions>

                                 <ContentPresenter HorizontalAlignment="Stretch" VerticalAlignment="Stretch" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />

                                 <Grid x:Name="arrowGlyph" IsHitTestVisible="False" Grid.Column="1" Margin="5">
                                    <Path Width="7" Height="4" Data="M 0,1 C0,1 0,0 0,0 0,0 3,0 3,0 3,0 3,1 3,1 3,1 4,1 4,1 4,1 4,0 4,0 4,0 7,0 7,0 7,0 7,1 7,1 7,1 6,1 6,1 6,1 6,2 6,2 6,2 5,2 5,2 5,2 5,3 5,3 5,3 4,3 4,3 4,3 4,4 4,4 4,4 3,4 3,4 3,4 3,3 3,3 3,3 2,3 2,3 2,3 2,2 2,2 2,2 1,2 1,2 1,2 1,1 1,1 1,1 0,1 0,1 z" Fill="#FF000000" />
                                 </Grid>
                              </Grid>
                           </chrome:ButtonChrome>
                        </Grid>
                     </ControlTemplate>
                  </Setter.Value>
               </Setter>
            </Style>

            <SolidColorBrush x:Key="ListItemHover" Color="#FFE7F5FD" />

            <Style x:Key="TimeItemStyle" TargetType="ListBoxItem">
               <Setter Property="Template">
                  <Setter.Value>
                     <ControlTemplate TargetType="ListBoxItem">
                        <Border Name="Border" SnapsToDevicePixels="true">
                           <ContentPresenter Margin="4" />
                        </Border>
                        <ControlTemplate.Triggers>
                           <Trigger Property="IsMouseOver" Value="True">
                              <Setter TargetName="Border" Property="Background" Value="{StaticResource ListItemHover}" />
                           </Trigger>
                           <Trigger Property="IsSelected" Value="True">
                              <Setter TargetName="Border" Property="Background" Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}" />
                              <Setter Property="Foreground" Value="White" />
                           </Trigger>
                        </ControlTemplate.Triggers>
                     </ControlTemplate>
                  </Setter.Value>
               </Setter>
            </Style>

            <ControlTemplate x:Key="fixedTimePickerTemplate"
                             TargetType="xctk:TimePicker">
               <Border>
                  <Grid>
                     <Grid>
                        <Grid.ColumnDefinitions>
                           <ColumnDefinition Width="*" />
                           <ColumnDefinition Width="Auto" />
                        </Grid.ColumnDefinitions>
                        <local:MyDateTimeUpDown x:Name="PART_TimeUpDown" 
                                                BorderThickness="1,1,0,1"
                                                Background="{TemplateBinding Background}"
                                                Foreground="{TemplateBinding Foreground}"
                                                ContextMenu="{TemplateBinding ContextMenu}"
                                                AllowSpin="{TemplateBinding AllowSpin}"
                                                Format="{TemplateBinding Format, Converter={StaticResource TimeFormatToDateTimeFormatConverter}}"
                                                FormatString="{TemplateBinding FormatString}"
                                                ShowButtonSpinner="{TemplateBinding ShowButtonSpinner}"
                                                Value="{Binding Value, RelativeSource={RelativeSource TemplatedParent}}"
                                                Watermark="{TemplateBinding Watermark}"
                                                WatermarkTemplate="{TemplateBinding WatermarkTemplate}" />
                        <ToggleButton x:Name="_timePickerToggleButton"
                                      Grid.Column="1"
                                      IsChecked="{Binding IsOpen, RelativeSource={RelativeSource TemplatedParent}}"
                                      Style="{StaticResource TimePickerToggleButtonStyle}"
                                      IsHitTestVisible="{Binding IsOpen, RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource InverseBoolConverter}}" />
                     </Grid>
                     <Popup IsOpen="{Binding IsChecked, ElementName=_timePickerToggleButton}"
                            StaysOpen="False">
                        <Border BorderThickness="1" Background="{StaticResource PopupBackgroundBrush}" BorderBrush="{StaticResource PopupDarkBorderBrush}">
                           <Grid>
                              <ListBox x:Name="PART_TimeListItems"
                                       BorderThickness="0"
                                       Width="150"
                                       Height="130"
                                       DisplayMemberPath="Display"
                                       ItemContainerStyle="{StaticResource TimeItemStyle}" />
                           </Grid>
                        </Border>
                     </Popup>
                  </Grid>
               </Border>
            </ControlTemplate>

            <Style TargetType="xctk:TimePicker"
                   BasedOn="{StaticResource {x:Type xctk:TimePicker}}">
               <Setter Property="Template"
                       Value="{StaticResource fixedTimePickerTemplate}" />
            </Style>
         </Style.Resources>
      </Style>
   </Window.Resources>

   <StackPanel>
      <xctk:DateTimePicker IsReadOnly="False"
                           Style="{StaticResource dateTimePickerStyle}" />
   </StackPanel>
</Window>

 

I hope this will meet your needs.

May 17, 2012 at 5:59 PM

I did something like this. I wanted times to round up (or down) to the nearest five minutes, then increase (or decrease) by increments of five. 

So if the time was 9:37 and they clicked up, it would display 9:40, then 9:45, 9:50 etc.

Here is the code and the extension method:

private DateTime SpinnerHelper(DateTime time, Xceed.Wpf.Toolkit.SpinEventArgs e)
{
	if (e.Direction == Xceed.Wpf.Toolkit.SpinDirection.Increase)
	{
		return time.AddMinutesRoundUp(5);
	}
	else
	{
		return time.AddMinutesRoundUp(-5);
	}
}

 

/// <summary>
/// Adds or subtracts a value to a date time rounding it to
/// multiples of the entered value
/// </summary>
/// <param name="dt">this</param>
/// <param name="value">Amount to add or subtract</param>
/// <returns>Adjusted DateTime</returns>
/// <history>
///     [Tim Hibbard]   04/08/2011  Created
/// </history>
public static DateTime AddMinutesRoundUp(this DateTime dt, int value)
{
    int delta = dt.Minute % value;
    int subtractDeltaFrom = 0;
    //since value to add is negative, we want to round down
    //to nearest delta value
    if (value < 0)
    {
        //but only if delta is more than 0. If delta is 0, 
        //then we are already rounded down
        if (delta > 0)
        {
            subtractDeltaFrom = Math.Abs(value); 
        }
                
    }
    return dt.AddMinutes(subtractDeltaFrom - delta).AddMinutes(value);
}