Custom Slider Control – Overview
This is part 1 of a multi-part article on a custom Slider control. You can find the other articles here:
- Overview
- The Base Class
The source code is now available on CodePlex.
As I promised, here is the initial post in a series that I plan on writing that covers the Slider control that I created for Berico Tailored Systems (BTS). This is the control that I entered into the Silverlight Control Contest and that I blogged about earlier.
This custom Slider came about because of an application (SnagL) that I have been working on for Berico Tailored Systems (BTS). Several of the application’s requirements dictated the need for a slider with additional functionality, primary the ability to provide a range of values rather than just a single value. My initial plan was to simply subclass the existing Microsoft Slider control and make the required changes to include the additional Thumb control. I also decided to add handles at either end of the slider to make the control more standardizes (as most sliders have these handles for increasing and decreasing the value of the slider). I quickly found out that I couldn’t do this by inheriting from the existing Slider control. The root of the problem is in the UpdateTrackLayout method. The purpose of this method is to appropriately layout the controls along the track as the slider is updated. Some of the calculations used in this method use ActualWidth and ActualHeight, which refers to the width and height of the control itself and not just the track that the Thumb controls are on. Adding the handles to the either end of the track changes the overall size of the control which causes the calculations to be off. Since this method is marked as internal, it cannot be overridden by our class. I was forced to create the updated Slider control from scratch.
Since I was starting from scratch I figured I would design the control from the ground up and look at what is available to sliders in other applications. I will say from the start that much of the code that was used for the Microsoft slider was reused for this control, although it was greatly altered. Here are the main requirements I decided on:
- Provide functionality to select a range
- Provide a way to switch from a regular slider to a range slider
- Provide an increase and decrease handle
- Provide a way to turn handles on and off
- Support all the standard slider functionality such as Orientation, IsDirectionReversed and IsEnabled
- Support styling and custom styles and templates
- Work with the Visual Studio IDE and Expression Blend
- Display tooltips over the Thumbs during dragging
Below is a sample Silverlight application that demonstrates this new Slider control. Obviously, you will need the Silverlight plugin installed to be able to see it.
The two horizontal sliders have been fully restyled while the two vertical ones are using the default template. Ignoring the details on the styling, the code snippet below shows the XAML used to create all 4 of the sliders.
<Berico:Slider x:Name="TestH1" Style="{StaticResource FancySliderStyle}" IsEnabled="true" Grid.Column="1" Grid.Row="1" IsRangeEnabled="False" Value="5" />
<Berico:Slider x:Name="TestH2" Style="{StaticResource FancySliderStyle}" IsEnabled="true" Grid.Column="1" Grid.Row="2" IsRangeEnabled="True" />
<Berico:Slider x:Name="TestV1" IsEnabled="true" Grid.Column="2" Grid.Row="1" Grid.RowSpan="2" IsRangeEnabled="false" Value="5" Orientation="Vertical" />
<Berico:Slider x:Name="TestV2" IsEnabled="true" Grid.Column="3" Grid.Row="1" Grid.RowSpan="2" IsRangeEnabled="True" LowerRangeValue="2" UpperRangeValue="8" Orientation="Vertical" />
I finally got around to setting up a CodePlex project for the custom controls (including this Slider) that I have been working on. I will update it as often as I can.
The main twin slider works great, but when you switch to single slider mode programmatically, then try to set the Value Property, the HorizontalThumb sub-control’s position doesn’t update to reflect the change in the way that the HorizontalLowerThumb and HorizontalUpperThumb controls intrinsically update their positions to reflect the values of LowerRangeValue UpperRangeValue respectively. The basic Silverlight Slider control does work this was – you update the Value Property, and the Thumb moves to reflect that change in state.
Actually, please ignore my comment above. I just checked your original control, which works fine. It’s only a control that I’ve derived from yours that doesn’t work. My derived control retains much of the same functionality provided by your control, with two Thumbs on one Slider, but takes out some of the ‘range’ concept visualisations, just leaving two inter-related Properties, one of which cannot be set to exceed the other, that are represented by two Thumbs on the one Slider. In some modes of my derived control, I need to allow for there only being one Thumb on the Slider, for which cases I switch your IsRangeEnabled Property to False. I find that, in my derived control, doing that causes the Thumb position not to update when I subsequently set the Value, for some reason. However, having just done some experiments with your original control, it’s clearly only my control that’s not working; the original RangeSlider works fine in Single Thumb mode.
Well, I am glad the RangeSlider isn’t the issue but I am sorry you are having an issue at all. I know that it can be frustrating. I don’t know enough about what you are trying to do to help much. What functionality does your derrived control add? If it isn’t adding any actual functionality, you might be able to get away with just restyling the control rather than creating a new control. For instance, if you don’t want to the range filler bar appearing, just replace it with a rectangle that has no border and is transparent. Everything would still operate the same but you wouldn’t see the range bar.