As I mentioned in my introduction to this series, I’m going over various aspects of how I created a DateTime Range slider control. In this article, I’m going to be going over the basics of creating the user control. Source for this project can be found on CodePlex.
First, to get two thumbs onto the slider, I overrode the control template of the regular slider with a template called “simpleSlider” to get rid of the track of each slider as well as some other default pieces of the base control template such as the repeater buttons. With these things there, one or the other of the sliders would sit on top of the other and really just mess with my users’ experience.
- <ControlTemplate x:Key=“simpleSlider” TargetType=”{x:Type Slider}“>
- <Border SnapsToDevicePixels=“true” BorderBrush=”{TemplateBinding BorderBrush}“ BorderThickness=”{TemplateBinding BorderThickness}“>
- <Grid>
- <Grid.RowDefinitions>
- <RowDefinition Height=“Auto”/>
- <RowDefinition Height=“Auto” MinHeight=”{TemplateBinding MinHeight}“/>
- <RowDefinition Height=“Auto”/>
- </Grid.RowDefinitions>
- <Rectangle x:Name=“PART_SelectionRange”/>
- <Track x:Name=“PART_Track” Grid.Row=“1”>
- <Track.Thumb>
- <Thumb x:Name=“Thumb” Style=”{StaticResource ResourceKey=HorizontalSliderThumbStyle}“ />
- </Track.Thumb>
- </Track>
- </Grid>
- </Border>
- </ControlTemplate>
Then my control is made with the two sliders that use the “simpleSlider” template and a single Border control to be my track for the two sliders:
- <Grid VerticalAlignment=“Center” Background=“Transparent”>
- <Border BorderThickness=“0,1,0,0” BorderBrush=“DarkGray” VerticalAlignment=“Bottom” Height=“1” HorizontalAlignment=“Stretch”
- Margin=“0,0,0,10”/>
- <Slider x:Name=“LowerSlider” VerticalAlignment=“Top” IsEnabled=”{Binding ElementName=root, Path=IsLowerSliderEnabled, Mode=TwoWay}“
- Minimum=”{Binding ElementName=root, Path=Minimum, Converter={StaticResource ResourceKey=dtdConverter}}“
- Maximum=”{Binding ElementName=root, Path=Maximum, Converter={StaticResource ResourceKey=dtdConverter}}“
- Value=”{Binding ElementName=root, Path=LowerValue, Mode=OneWay, Converter={StaticResource ResourceKey=dtdConverter}}“
- Template=”{StaticResource simpleSlider}“
- Margin=“0,0,10,0”
- SmallChange=”{Binding ElementName=root, Path=SmallChange, Converter={StaticResource ResourceKey=timespanToDoubleConverter}}“
- LargeChange=”{Binding ElementName=root, Path=LargeChange, Converter={StaticResource ResourceKey=timespanToDoubleConverter}}“
- />
- <Slider x:Name=“UpperSlider” IsEnabled=”{Binding ElementName=root, Path=IsUpperSliderEnabled, Mode=TwoWay}“
- Minimum=”{Binding ElementName=root, Path=Minimum, Converter={StaticResource ResourceKey=dtdConverter}}“
- Maximum=”{Binding ElementName=root, Path=Maximum, Converter={StaticResource ResourceKey=dtdConverter}}“
- Value=”{Binding ElementName=root, Path=UpperValue, Mode=OneWay, Converter={StaticResource ResourceKey=dtdConverter}}“
- Template=”{StaticResource simpleSlider}“
- Margin=“10,0,0,0”
- SmallChange=”{Binding ElementName=root, Path=SmallChange, Converter={StaticResource ResourceKey=timespanToDoubleConverter}}“
- LargeChange=”{Binding ElementName=root, Path=LargeChange, Converter={StaticResource ResourceKey=timespanToDoubleConverter}}“
- />
- </Grid>
Mainly because I didn’t want to spend the time (at this point) dealing with making this a slider that could handle more than just a DateTime range, the Minimum, Maximum, and Value properties of the sliders are using an IValueConverter to handle the conversion between the doubles the sliders expose to DateTime values. The SmallChange and LargeChange properties are converted from TimeSpans my control expects to doubles that the slider controls expect.
- public class DateTimeDoubleConverter : IValueConverter
- {
- public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
- {
- DateTime dt = DateTime.Parse(value.ToString());
- return dt.Ticks;
- }
- public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
- {
- double d = double.Parse(value.ToString());
- return new DateTime((long)d);
- }
- }
- public class TimeSpanToDoubleConverter : IValueConverter
- {
- public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
- {
- TimeSpan givenValue = (TimeSpan)value;
- return givenValue.Ticks;
- }
- public object ConvertBack(object value, Type targetType,
- object parameter, System.Globalization.CultureInfo culture)
- {
- return new TimeSpan(((long)value));
- }
- }