How to snap to the values on a WPF slider, but only show a tick for some of them
I hav开发者_运维问答e a WPF slider whose minimum value = 0 and maximum value = 50. I want to show ticks at an interval of 5, but have the slider snap at an interval of 1. Is this even possible?
The property Interval
does not affect this behaviour.
Use this:
<Slider TickFrequency="5" IsSnapToTickEnabled="True" />
<Slider TickPlacement="TopLeft" Minimum="0" Maximum="50" TickFrequency="5" IsSnapToTickEnabled="False" SmallChange="1" />
Disable snapping to ticks with IsSnapToTickEnabled="False"
and set SmallChange="1"
.
SmallChange determines the increment when dragging the thumb or pressing the arrow keys. You can also control the increment when the user clicks on the slider (not on the thumb). To make the thumb jump, use LargeChange="10"
to jump 10 units. To make the slider move to where the user clicked, use IsMoveToPointEnabled="True"
. Note, IsMoveToPointEnabled will place the thumb at the nearest SmallChange increment.
The normal WPF Slider
can only draw all tick marks or none at all.
To work around this limitation you can either create your own Slider
or you can use a trick: Disable the Slider
's TickBar
and draw your own.
<StackPanel>
<TickBar Maximum="{Binding Path=Maximum, ElementName=MySlider}"
Minimum="{Binding Path=Minimum, ElementName=MySlider}" TickFrequency="5" Height="4"
Fill="Black" ReservedSpace="11" />
<Slider Name="MySlider" Maximum="50" TickPlacement="None" IsSnapToTickEnabled="True" />
</StackPanel>
ReservedSpace
is the combined space to the left and right of the outer most ticks, which is exactly the same as the Thumb
's width. It is usually 11 pixel. If you use an unusual theme or messed around with it in another way, you have to adjust it in your new TickBar
as well.
This solution has one disadvantage: The Thumb
will not be pointy, because the Slider
thinks, that he has no tick marks. If you want the Thumb
to be pointy, you have to trick the Slider
by giving him a TickBar
and then collapse it later:
<StackPanel>
<TickBar Maximum="{Binding Path=Maximum, ElementName=MySlider2}"
Minimum="{Binding Path=Minimum, ElementName=MySlider2}" TickFrequency="5"
Height="4" Fill="Black" ReservedSpace="11" />
<Slider Name="MySlider2" Maximum="50" TickPlacement="TopLeft"
IsSnapToTickEnabled="True"/>
</StackPanel>
And then in your Window
's constructor (after InitializeComponent()
):
this.Loaded += (sender, e) =>
{
var sliderTickBar = (MySlider2.Template.FindName("TopTick", MySlider2) as
System.Windows.Controls.Primitives.TickBar);
sliderTickBar.Visibility = Visibility.Collapsed;
};
I solved the same issue by displaying only the ticks I wanted by setting the Ticks property, setting IsSnapToTickEnabled to false and using rounding in the binding of the slider value. In my example I want to show slider for 0 to 100%, display ticks in 5% increments and snap step to 1%.
The XAML:
<Slider Minimum="0" Maximum="100"
TickPlacement="BottomRight" Ticks="{Binding PercentTicks}"
TickFrequency="1" SmallChange="1" LargeChange="5"
Value="{Binding MyProperty, Converter={StaticResource PercentageConverter}}" />
The view model:
public double MyProperty
{
get { return myProperty; }
set
{
myProperty = Math.Round(value, 2);
OnPropertyChanged();
}
}
myProperty has value from 0 to 1, so rounding to 2 digits gives exactly 1% step! Setting the ticks to 5% increments is done in the view model's constructor:
var ticks = new DoubleCollection();
for (int i = 0; i <= 100; i+=5)
{
ticks.Add(i);
}
PercentTicks = ticks;
精彩评论