Yesterday, I posted about how to
Create a Range Slider in WPF using composition within a UserControl.
Today, I want to do the same in Silverlight and
_try_ to use the same technique(s).
The obvious things that need to change are:
- The Slider ControlTemplate
- Removing the ElementName binding
I can hear you all now: "No! Josh! Silverlight 3 has ElementName binding support! You don't need to remove it! Nooooo!".
Sadly though, we can't use it the way I did in
yesterday's post. Let's recap the big tip I was using:
<UserControl x:Class="UserControlFun.RangeSlider"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Name="root">
<Slider x:Name="LowerSlider"
Minimum="{Binding ElementName=root, Path=Minimum}"
Maximum="{Binding ElementName=root, Path=Maximum}"
Value="{Binding ElementName=root, Path=LowerValue}" />
<Slider x:Name="UpperSlider"
Minimum="{Binding ElementName=root, Path=Minimum}"
Maximum="{Binding ElementName=root, Path=Maximum}"
Value="{Binding ElementName=root, Path=UpperValue}" />
</UserControl>
As you can see we give the UserControl element a name. This is supported in WPF but not recommended in Silverlight. This is because in Silverlight an element can only have one name and therefore if we specify a Name where we use the control, like this:
<local:RangeSlider x:Name="overridingName" />
the internal ElementName binding will now fail (silently) because we changed the name. One solution might be to *not* rename the element where it's used but there's another problem: we can only use this control once or we'll have two elements with the same name.
This is very sad and I hope this is fixed in future releases. However, there is a workaround that seems to achieve what I want to achieve.
The trick is to use ambient binding (no ElementName) by programmatically setting the DataContext in the control's constructor:
public RangeSlider()
{
InitializeComponent();
this.Loaded += new RoutedEventHandler(RangeSlider_Loaded);
LayoutRoot.DataContext = this;
}
Notice that we specifically don't set
this.DataContext = this;. That would break any bindings specified on the UserControl externally. Instead, we head for the first child of our UserControl - in this case, called 'LayoutRoot'.
Here's the Xaml for the UserControl:
<UserControl x:Class="UserControlFunSL3.RangeSlider"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" >
<Grid x:Name="LayoutRoot" VerticalAlignment="Top">
<!-- resources will go here -->
<Border BorderThickness="0,1,0,0" BorderBrush="Black" VerticalAlignment="Center" Height="1" Margin="5,0,5,0"/>
<Slider x:Name="LowerSlider"
Minimum="{Binding Minimum}"
Maximum="{Binding Maximum}"
Value="{Binding LowerValue, Mode=TwoWay}"
Margin="0,0,10,0"
Template="{StaticResource sliderTemplate}"
/>
<Slider x:Name="UpperSlider"
Minimum="{Binding Minimum}"
Maximum="{Binding Maximum}"
Value="{Binding UpperValue, Mode=TwoWay}"
Margin="10,0,0,0"
Template="{StaticResource sliderTemplate}"
/>
</Grid>
</UserControl>
Finally, we need our Silverlight specific Slider Template:
<Grid.Resources>
<ControlTemplate x:Key="buttonTemplate" TargetType="RepeatButton">
<!-- just empty-->
<Grid />
</ControlTemplate>
<ControlTemplate x:Key="sliderTemplate" TargetType="Slider">
<Grid x:Name="HorizontalTemplate" Background="{TemplateBinding Background}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<RepeatButton Template="{StaticResource buttonTemplate}" IsTabStop="False" IsEnabled="False" x:Name="HorizontalTrackLargeChangeDecreaseRepeatButton" Grid.Column="0"/>
<Thumb IsTabStop="True" Height="18" x:Name="HorizontalThumb" Width="11" Grid.Column="1">
<Thumb.Template>
<ControlTemplate TargetType="Thumb">
<Rectangle Fill="Red"
Stroke="Black"
StrokeThickness="1" />
</ControlTemplate>
</Thumb.Template>
</Thumb>
<RepeatButton Template="{StaticResource buttonTemplate}" IsTabStop="False" IsEnabled="False" x:Name="HorizontalTrackLargeChangeIncreaseRepeatButton" Grid.Column="2"/>
</Grid>
</ControlTemplate>
</Grid.Resources>
And we're done. Almost everything else is the same as our WPF control. Why not have a play with the control right here:
Or, get the source here: Download Source (7KB). Usual disclaimers for demoware apply.

Post By
Josh Twist
4:12 AM
16 Jul 2009
» Next Post:
Bindorama - Binding Craziness now for Silverlight too!
« Previous Post:
Creating a Range Slider in WPF (and other cool tips and tricks for UserControls)
Comments are closed for this post.
Posted by
Rob
@
16 Jul 2009
6:57 AM
This gotcha is a fine example the consequence of Silverlight's lack of NameScopes.
Posted by
Ole Jak
@
05 Oct 2009
1:50 PM
Maybe there should be a middle resizing point like here
http://dougmccune.com/blog/2007/01/21/draggable-slider-component-for-flex/
Posted by
andrew
@
07 Dec 2009
11:31 AM
very gooood :))
Posted by
GAUTAM
@
15 Apr 2010
12:51 AM
Hi
i am using this user control in application.i am facing problem in implementation .describing my scenerio..
i want to use range slider on dev.xaml in which already some filter is working besides all these range filter i wnat to use .on dev.xaml page i use the
<local:RangeSlider x:Name="slider" Margin="273,10,0,10" Minimum="0" Maximum="10" Height="27" HorizontalAlignment="Left" Width="136" />
on the usercontrol page range.xaml event are there on valuechanged but i want to use this event on my dev.xaml page how i will do this ...
Thanks
Posted by
Hrishi
@
21 Jan 2011
2:06 PM
@Ole Jak:
Can you explain how can we create slider like link you have shared?
http://dougmccune.com/blog/2007/01/21/draggable-slider-component-for-flex/
Posted by
gj
@
09 May 2011
6:21 PM
this is exactly what i am looking for, but i need vertical
i change everything horizontal to vertical, margins, left to top,...
anyway, i cannot get it to work vertically. any suggestions, or does source for that exist?
Posted by
Aj
@
25 May 2011
1:42 PM
Thanks for the post. I needed such a control for my application and tried using this. But when I have the Minimum value as negative it is not working. Any guess why.
Posted by
Bob
@
08 Sep 2011
2:12 PM
The range slider doesn't work if I change the minimum to anything other than 0, could you please check why it only works for the slider range from zero? Thanks!
Posted by
Yauhen Safrankou
@
25 Dec 2011
3:35 PM
First of all, I thank Josh for sharing such control. I easily integrated the Range Slider control into my application and managed to use it with Minimum value other than 0. The control works when you specify Minimum and Maximum in exactly the right order: first Maximum and then Minimum! For the explanation, please refer to
http://dotnetbyexample.blogspot.com/2009/08/bind-silverlight-3-slider-value-minimum.html