Controls
Slider
Slider is a templated range control for selecting a numeric value by dragging a thumb, clicking along a track, or using the keyboard. It supports horizontal and vertical orientations, visible ticks, selection ranges, auto-tooltips, and WPF-style command-driven stepping.
Quick start
Use Slider when the user should set a numeric value by dragging a thumb or clicking along a track. It is a better fit than ScrollBar when the control represents a value such as volume, opacity, zoom, or a tuning parameter instead of a viewport moving through content.
Minimal horizontal slider
<Slider Width="240"
Minimum="0"
Maximum="100"
Value="35" />
Vertical slider
<Slider Height="180"
Orientation="Vertical"
Minimum="-1"
Maximum="1"
Value="0.25" />
Styled slider
<Slider Width="280"
Minimum="0"
Maximum="1"
Value="0.6"
Background="#0F1720"
TrackBrush="#2F475C"
ThumbBrush="#76D0FF"
BorderBrush="#4E6D85"
TrackThickness="6"
ThumbSize="18" />
Choose the right range control: use Slider for selecting a value. Use ScrollBar when the range is a viewport offset through a larger extent, and use ProgressBar when the user should see progress without direct manipulation.
Range model
Slider inherits the shared range model used by the framework's other range controls. Minimum, Maximum, and Value are always kept in a legal state, and the effective value is what drives thumb position, tick snapping, automation, and routed change notifications.
Lower and upper bounds
Minimum defaults to 0 and Maximum defaults to 10. If you assign them in reverse order, the control coerces them back into ascending order.
Current value
Value defaults to 0 and is clamped into the effective range every time it changes, whether the change comes from code, thumb drag, or track interaction.
Horizontal direction
For a horizontal slider, lower values render on the left and higher values render on the right.
Vertical direction
For a vertical slider, lower values render at the bottom and higher values render at the top. Dragging upward increases the value.
<Slider Width="260"
Minimum="-200"
Maximum="200"
Value="0" />
That slider places 0 in the center of the range. Moving the thumb right produces positive values. Moving it left produces negative values.
Interaction model
Slider supports both pointer interaction and keyboard commands. Pointer input is routed through the thumb, track, and repeat-button regions inside the template. Keyboard input is exposed through command bindings so arrow keys, page keys, and home/end follow slider semantics automatically when the control has focus.
Thumb drag
Dragging begins only when the pointer goes down on the thumb itself. While dragging, the control tracks pointer movement and continuously updates Value.
Track click
If the pointer goes down on the track outside the thumb and IsMoveToPointEnabled is false, the control moves the value by LargeChange toward the clicked side.
Move to point
If IsMoveToPointEnabled is true, clicking the track jumps the thumb to the clicked position instead of applying a page-sized step.
Keyboard stepping
Arrow keys use SmallChange, PageUp and PageDown use LargeChange, and Home and End jump directly to Minimum and Maximum.
var slider = new Slider
{
Width = 260f,
Minimum = 0f,
Maximum = 1f,
Value = 0.5f,
SmallChange = 0.05f,
LargeChange = 0.1f,
IsMoveToPointEnabled = true
};
slider.ValueChanged += (_, _) =>
{
selectionOpacity = slider.Value;
};
Ticks and snapping
The control supports both frequency-based ticks and explicit tick collections through TickFrequency, Ticks, and IsSnapToTickEnabled. Snapping is applied after value coercion, so direct assignment, keyboard input, and pointer interaction all land on the nearest effective tick when snapping is enabled.
Tick sources
If Ticks contains values, the slider snaps against that explicit list plus the range endpoints. If the collection is empty, TickFrequency generates evenly spaced ticks from Minimum to Maximum.
Visible ticks
TickPlacement renders tick marks above or below a horizontal slider, or on either side of a vertical slider. TickPlacement.Both renders mirrored tick bars.
<StackPanel>
<TextBlock Text="Selection opacity" Margin="0,0,0,6" />
<Slider Width="260"
Minimum="0.15"
Maximum="1"
Value="0.65"
TickFrequency="0.05"
TickPlacement="Both"
IsSnapToTickEnabled="True"
AutoToolTipPlacement="TopLeft" />
</StackPanel>
This mirrors the pattern used in the rich text demo surface, where a slider snaps the editor's selection opacity to predictable increments.
Selection range and direction
Slider can visualize a selected interval separately from the current thumb value. It can also reverse its direction without changing the numeric range itself, which is useful for alternative scrubbers and mirrored layouts.
Selection band
Set IsSelectionRangeEnabled to show a highlighted band inside the track. SelectionStart and SelectionEnd are coerced into the slider range and laid out against the resolved track geometry.
Horizontal reversal
On a horizontal slider, IsDirectionReversed swaps the usual left-to-right mapping so larger values appear on the left.
Vertical default
Vertical sliders follow WPF's default bottom-to-top value flow. Dragging upward increases the value unless IsDirectionReversed is set.
Auto-tooltips
AutoToolTipPlacement shows a tooltip only while the thumb is being dragged. AutoToolTipPrecision controls the number formatting used for the displayed value.
<Slider Width="280"
Minimum="0"
Maximum="100"
Value="35"
TickPlacement="Both"
Ticks="0,10,20,40,60,80,100"
IsSnapToTickEnabled="True"
IsSelectionRangeEnabled="True"
SelectionStart="20"
SelectionEnd="80"
AutoToolTipPlacement="TopLeft" />
Template structure
Slider is a templated control. The default template is built around a root grid, a shared Track, a Thumb, track-side repeat regions, optional tick bars, and an optional selection range element. Custom templates can restyle the control, but they must preserve the required parts and their ownership rules.
Required parts
PART_Root, PART_Track, PART_Thumb, PART_DecreaseButton, and PART_IncreaseButton are part of the default template contract.
Optional parts
PART_SelectionRange, PART_TopTickBar, PART_BottomTickBar, PART_LeftTickBar, and PART_RightTickBar are optional, but the control will use them when present.
PART_Thumb,PART_DecreaseButton,PART_IncreaseButton, andPART_SelectionRangemust live insidePART_Track.- The track uses fixed-thumb slider layout rather than viewport-sized scrollbar layout.
- Tick bars sit outside the track and render against the same range, direction, and reserved thumb space.
Template example
<ControlTemplate TargetType="Slider">
<Grid x:Name="PART_Root">
<TickBar x:Name="PART_TopTickBar" />
<Track x:Name="PART_Track">
<Border x:Name="PART_SelectionRange" />
<RepeatButton x:Name="PART_DecreaseButton" />
<Thumb x:Name="PART_Thumb" />
<RepeatButton x:Name="PART_IncreaseButton" />
</Track>
<TickBar x:Name="PART_BottomTickBar" />
</Grid>
</ControlTemplate>
Layout and sizing
Slider participates in normal layout, but it also carries a few minimum expectations so the thumb and track remain usable when the parent does not constrain it tightly.
Desired size
Unconstrained horizontal sliders ask for at least 120 units of width. Unconstrained vertical sliders ask for at least 120 units of height.
Track thickness
TrackThickness defaults to 4 and is coerced to at least 1. The track is centered inside the control's cross-axis slot.
Thumb size
ThumbSize defaults to 14 and is coerced to at least 6. The thumb stays fixed-size and its center can still reach the exact minimum and maximum positions.
Tick placement
TickPlacement adds extra rows or columns around the track so ticks can render above, below, left, right, or on both sides of the control.
<StackPanel Orientation="Horizontal">
<Slider Width="240"
Height="30"
Minimum="0"
Maximum="100"
Value="35" />
<Slider Width="28"
Height="180"
Margin="16,0,0,0"
Orientation="Vertical"
Minimum="0"
Maximum="100"
Value="65" />
</StackPanel>
Property and event reference
Range properties
Orientation: Horizontal or Vertical. Default: Horizontal.
Minimum: lower bound of the range. Default: 0.
Maximum: upper bound of the range. Default: 10.
Value: current selected value. Default: 0.
IsDirectionReversed: flips the rendered direction of the track. Default: false.
Interaction properties
LargeChange: amount applied for track clicks when move-to-point is disabled. Default: 1.
SmallChange: keyboard and command step size. Default: 1.
IsMoveToPointEnabled: when true, clicking the track jumps to that position. Default: false.
Delay / Interval: repeat timing for held track presses. Defaults: 250 / 100 milliseconds.
ValueChanged: routed event raised when the effective value changes.
Tick behavior
IsSnapToTickEnabled: enables snapping to the nearest tick. Default: false.
TickFrequency: distance between ticks. Default: 1.
Ticks: explicit tick collection used for snapping and tick rendering.
TickPlacement: controls where tick marks render. Default: None.
Selection and tooltip
IsSelectionRangeEnabled: enables the selection-range visual band.
SelectionStart / SelectionEnd: selection range bounds, coerced into the slider range.
AutoToolTipPlacement: shows a drag-only tooltip above/below or left/right of the thumb. Default: None.
AutoToolTipPrecision: decimal precision used when formatting the tooltip value.
Rendering surface
Background: template root fill. Default: (20, 20, 20).
TrackBrush: track fill. Default: (62, 62, 62).
ThumbBrush: thumb fill. Default: (140, 140, 140).
SelectionRangeBrush: fill used for the selection range band.
BorderBrush: outline color for the track and thumb. Default: (100, 100, 100).
TrackThickness: centered track thickness. Default: 4.
ThumbSize: square thumb size. Default: 14.
Patterns and examples
Volume slider
<StackPanel>
<TextBlock Text="Master volume" Margin="0,0,0,6" />
<Slider Width="280"
Minimum="0"
Maximum="1"
Value="0.72"
TickFrequency="0.05"
IsSnapToTickEnabled="True" />
</StackPanel>
Keyboard-friendly range selector
<Slider Width="280"
Minimum="0"
Maximum="100"
Value="40"
SmallChange="5"
LargeChange="20" />
When this slider has focus, arrow keys step by 5, page keys step by 20, and home/end jump to the ends of the range.
Jump-to-position scrubber
<Slider Width="420"
Minimum="0"
Maximum="300"
Value="42"
LargeChange="15"
IsMoveToPointEnabled="True"
AutoToolTipPlacement="BottomRight"
TrackThickness="5"
ThumbSize="16" />
Selection-range slider
<Slider Width="280"
Minimum="0"
Maximum="100"
Value="35"
TickPlacement="Both"
Ticks="0,10,20,40,60,80,100"
IsSnapToTickEnabled="True"
IsSelectionRangeEnabled="True"
SelectionStart="20"
SelectionEnd="80" />
Vertical parameter control
<Border Width="48"
Height="220"
Padding="10"
Background="#111923"
BorderBrush="#34495B"
BorderThickness="1">
<Slider Width="28"
Height="200"
Orientation="Vertical"
Minimum="0"
Maximum="100"
Value="80"
Background="#111923"
TrackBrush="#3E556B"
ThumbBrush="#F0B45A"
BorderBrush="#5B748C" />
</Border>
Code-driven setup
var opacitySlider = new Slider
{
Width = 260f,
Minimum = 0.15f,
Maximum = 1f,
TickFrequency = 0.05f,
IsSnapToTickEnabled = true,
Value = 0.65f,
Background = new Color(15, 23, 32),
TrackBrush = new Color(47, 71, 92),
ThumbBrush = new Color(118, 208, 255),
BorderBrush = new Color(78, 109, 133)
};
opacitySlider.ValueChanged += (_, _) =>
{
editor.SelectionOpacity = opacitySlider.Value;
};
Automation
Slider participates in the framework automation surface as a writable range control. Its automation peer exposes Minimum, Maximum, and Value, and automation clients can set the current numeric value through the range-value provider.
Notes and pitfalls
Tick snapping includes the endpoints. Whether ticks come from TickFrequency or an explicit Ticks collection, Minimum and Maximum are still considered valid snap candidates.
Selection range is visual only. SelectionStart and SelectionEnd do not clamp Value; they only control the highlighted interval drawn inside the track.
Styling properties resolve to colors, not brush objects. Use values that convert to Color for Background, TrackBrush, ThumbBrush, SelectionRangeBrush, and BorderBrush.
Template ownership matters. If you replace the template, keep the thumb and track-side repeat regions inside PART_Track; the control depends on that structure for layout and hit handling.
Vertical sliders already invert the underlying track direction. That is how the control preserves WPF-style bottom-to-top value flow by default. Setting IsDirectionReversed flips that behavior again.