Browse Source

Import Fluent Slider

Jumar Macato 5 years ago
parent
commit
9d5345e621

+ 2 - 0
samples/ControlCatalog/Pages/SliderPage.xaml

@@ -9,12 +9,14 @@
       <Slider Value="0"
               Minimum="0"
               Maximum="100"
+              TickFrequency="10"
               Width="300"/>
       <Slider Value="0"
               Minimum="0"
               Maximum="100"
               Orientation="Vertical"
               IsSnapToTickEnabled="True"
+              TickPlacement="Outside"
               TickFrequency="10"
               Height="300"/>
     </StackPanel>

+ 13 - 1
src/Avalonia.Controls/Primitives/Track.cs

@@ -41,13 +41,16 @@ namespace Avalonia.Controls.Primitives
         public static readonly StyledProperty<bool> IsDirectionReversedProperty =
             AvaloniaProperty.Register<Track, bool>(nameof(IsDirectionReversed));
 
+        public static readonly StyledProperty<bool> IgnoreThumbDragProperty =
+            AvaloniaProperty.Register<Track, bool>(nameof(IsThumbDragHandled));
+
         private double _minimum;
         private double _maximum = 100.0;
         private double _value;
 
         static Track()
         {
-            ThumbProperty.Changed.AddClassHandler<Track>((x,e) => x.ThumbChanged(e));
+            ThumbProperty.Changed.AddClassHandler<Track>((x, e) => x.ThumbChanged(e));
             IncreaseButtonProperty.Changed.AddClassHandler<Track>((x, e) => x.ButtonChanged(e));
             DecreaseButtonProperty.Changed.AddClassHandler<Track>((x, e) => x.ButtonChanged(e));
             AffectsArrange<Track>(MinimumProperty, MaximumProperty, ValueProperty, OrientationProperty);
@@ -113,6 +116,12 @@ namespace Avalonia.Controls.Primitives
             set { SetValue(IsDirectionReversedProperty, value); }
         }
 
+        public bool IsThumbDragHandled
+        {
+            get { return GetValue(IgnoreThumbDragProperty); }
+            set { SetValue(IgnoreThumbDragProperty, value); }
+        }
+
         private double ThumbCenterOffset { get; set; }
         private double Density { get; set; }
 
@@ -422,6 +431,9 @@ namespace Avalonia.Controls.Primitives
 
         private void ThumbDragged(object sender, VectorEventArgs e)
         {
+            if (IsThumbDragHandled)
+                return;
+                
             Value = MathUtilities.Clamp(
                 Value + ValueFromDistance(e.Vector.X, e.Vector.Y),
                 Minimum,

+ 102 - 53
src/Avalonia.Controls/Slider.cs

@@ -1,12 +1,40 @@
 using System;
+using Avalonia.Controls.Mixins;
 using Avalonia.Controls.Primitives;
-using Avalonia.Data;
 using Avalonia.Input;
 using Avalonia.Interactivity;
 using Avalonia.Layout;
+using Avalonia.Utilities;
 
 namespace Avalonia.Controls
 {
+
+    /// <summary>
+    /// Enum which describes how to position the ticks in a <see cref="Slider"/>.
+    /// </summary>
+    public enum TickPlacement
+    {
+        /// <summary>
+        /// No tick marks will appear.
+        /// </summary>
+        None,
+
+        /// <summary>
+        /// Tick marks  will appear above the track for a horizontal <see cref="Slider"/>, or to the left of the track for a vertical <see cref="Slider"/>.
+        /// </summary>
+        TopLeft,
+
+        /// <summary>
+        /// Tick marks will appear below the track for a horizontal <see cref="Slider"/>, or to the right of the track for a vertical <see cref="Slider"/>.
+        /// </summary>
+        BottomRight,
+
+        /// <summary>
+        /// Tick marks appear on both sides of either a horizontal or vertical <see cref="Slider"/>.
+        /// </summary>
+        Outside
+    }
+
     /// <summary>
     /// A control that lets the user select from a range of values by moving a Thumb control along a Track.
     /// </summary>
@@ -30,19 +58,31 @@ namespace Avalonia.Controls
         public static readonly StyledProperty<double> TickFrequencyProperty =
             AvaloniaProperty.Register<Slider, double>(nameof(TickFrequency), 0.0);
 
+        /// <summary>
+        /// Defines the <see cref="TickPlacement"/> property.
+        /// </summary>
+        public static readonly StyledProperty<TickPlacement> TickPlacementProperty =
+            AvaloniaProperty.Register<TickBar, TickPlacement>(nameof(TickPlacement), 0d);
+
         // Slider required parts
+        private bool _isDragging = false;
         private Track _track;
         private Button _decreaseButton;
         private Button _increaseButton;
+        private IDisposable _decreaseButtonPressDispose;
+        private IDisposable _decreaseButtonReleaseDispose;
+        private IDisposable _increaseButtonSubscription;
+        private IDisposable _increaseButtonReleaseDispose;
+        private IDisposable _pointerMovedDispose;
 
         /// <summary>
         /// Initializes static members of the <see cref="Slider"/> class. 
         /// </summary>
         static Slider()
         {
+            PressedMixin.Attach<Slider>();
             OrientationProperty.OverrideDefaultValue(typeof(Slider), Orientation.Horizontal);
             Thumb.DragStartedEvent.AddClassHandler<Slider>((x, e) => x.OnThumbDragStarted(e), RoutingStrategies.Bubble);
-            Thumb.DragDeltaEvent.AddClassHandler<Slider>((x, e) => x.OnThumbDragDelta(e), RoutingStrategies.Bubble);
             Thumb.DragCompletedEvent.AddClassHandler<Slider>((x, e) => x.OnThumbDragCompleted(e), RoutingStrategies.Bubble);
         }
 
@@ -81,57 +121,83 @@ namespace Avalonia.Controls
             set { SetValue(TickFrequencyProperty, value); }
         }
 
+        /// <summary>
+        /// Gets or sets a value that indicates where to draw 
+        /// tick marks in relation to the track.
+        /// </summary>
+        public TickPlacement TickPlacement
+        {
+            get { return GetValue(TickPlacementProperty); }
+            set { SetValue(TickPlacementProperty, value); }
+        }
+
         /// <inheritdoc/>
         protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
         {
-            if (_decreaseButton != null)
-            {
-                _decreaseButton.Click -= DecreaseClick;
-            }
-
-            if (_increaseButton != null)
-            {
-                _increaseButton.Click -= IncreaseClick;
-            }
+            _decreaseButtonPressDispose?.Dispose();
+            _decreaseButtonReleaseDispose?.Dispose();
+            _increaseButtonSubscription?.Dispose();
+            _increaseButtonReleaseDispose?.Dispose();
+            _pointerMovedDispose?.Dispose();
 
             _decreaseButton = e.NameScope.Find<Button>("PART_DecreaseButton");
             _track = e.NameScope.Find<Track>("PART_Track");
             _increaseButton = e.NameScope.Find<Button>("PART_IncreaseButton");
 
+            if (_track != null)
+            {
+                _track.IsThumbDragHandled = true;
+            }
+
             if (_decreaseButton != null)
             {
-                _decreaseButton.Click += DecreaseClick;
+                _decreaseButtonPressDispose = _decreaseButton.AddDisposableHandler(PointerPressedEvent, TrackPressed, RoutingStrategies.Tunnel);
+                _decreaseButtonReleaseDispose = _decreaseButton.AddDisposableHandler(PointerReleasedEvent, TrackReleased, RoutingStrategies.Tunnel);
             }
 
             if (_increaseButton != null)
             {
-                _increaseButton.Click += IncreaseClick;
+                _increaseButtonSubscription = _increaseButton.AddDisposableHandler(PointerPressedEvent, TrackPressed, RoutingStrategies.Tunnel);
+                _increaseButtonReleaseDispose = _increaseButton.AddDisposableHandler(PointerReleasedEvent, TrackReleased, RoutingStrategies.Tunnel);
             }
+
+            _pointerMovedDispose = this.AddDisposableHandler(PointerMovedEvent, TrackMoved, RoutingStrategies.Tunnel);
         }
 
-        private void DecreaseClick(object sender, RoutedEventArgs e)
+        private void TrackMoved(object sender, PointerEventArgs e)
         {
-            ChangeValueBy(-LargeChange);
+            if (_isDragging)
+            {
+                MoveToPoint(e.GetCurrentPoint(_track));
+            }
         }
 
-        private void IncreaseClick(object sender, RoutedEventArgs e)
+        private void TrackReleased(object sender, PointerReleasedEventArgs e)
         {
-            ChangeValueBy(LargeChange);
+            _isDragging = false;
         }
 
-        private void ChangeValueBy(double by)
+        private void TrackPressed(object sender, PointerPressedEventArgs e)
         {
-            if (IsSnapToTickEnabled)
+            if (e.GetCurrentPoint(this).Properties.IsLeftButtonPressed)
             {
-                by = by < 0 ? Math.Min(-TickFrequency, by) : Math.Max(TickFrequency, by);
+                MoveToPoint(e.GetCurrentPoint(_track));
+                _isDragging = true;
             }
+        }
 
-            var value = Value;
-            var next = SnapToTick(Math.Max(Math.Min(value + by, Maximum), Minimum));
-            if (next != value)
-            {
-                Value = next;
-            }
+        private void MoveToPoint(PointerPoint x)
+        {
+            var orient = Orientation == Orientation.Horizontal;
+            var pointDen = orient ? _track.Bounds.Width : _track.Bounds.Height;
+            var pointNum = orient ? x.Position.X : x.Position.Y;
+            var logicalPos = MathUtilities.Clamp(pointNum / pointDen, 0.0d, 1.0d);
+            var invert = orient ? 0 : 1;
+            var calcVal = Math.Abs(invert - logicalPos);
+            var range = Maximum - Minimum;
+            var finalValue = calcVal * range;
+
+            Value = IsSnapToTickEnabled ? SnapToTick(finalValue) : finalValue;
         }
 
         protected override void OnPropertyChanged<T>(AvaloniaPropertyChangedEventArgs<T> change)
@@ -150,19 +216,7 @@ namespace Avalonia.Controls
         /// <param name="e"></param>
         protected virtual void OnThumbDragStarted(VectorEventArgs e)
         {
-        }
-
-        /// <summary>
-        /// Called when user dragging the <see cref="Thumb"/>.
-        /// </summary>
-        /// <param name="e"></param>
-        protected virtual void OnThumbDragDelta(VectorEventArgs e)
-        {
-            Thumb thumb = e.Source as Thumb;
-            if (thumb != null && _track?.Thumb == thumb)
-            {
-                MoveToNextTick(_track.Value);
-            }
+            _isDragging = true;
         }
 
         /// <summary>
@@ -171,15 +225,7 @@ namespace Avalonia.Controls
         /// <param name="e"></param>
         protected virtual void OnThumbDragCompleted(VectorEventArgs e)
         {
-        }
-
-        /// <summary>
-        /// Searches for the closest tick and sets Value to that tick.
-        /// </summary>
-        /// <param name="value">Value that want to snap to closest Tick.</param>
-        private void MoveToNextTick(double value)
-        {
-            Value = SnapToTick(Math.Max(Minimum, Math.Min(Maximum, value)));
+            _isDragging = false;
         }
 
         /// <summary>
@@ -188,14 +234,17 @@ namespace Avalonia.Controls
         /// <param name="value">Value that want to snap to closest Tick.</param>
         private double SnapToTick(double value)
         {
-            if (IsSnapToTickEnabled && TickFrequency > 0.0)
+            var previous = Minimum;
+            var next = Maximum;
+
+            if (TickFrequency > 0.0)
             {
-                double previous = Minimum + (Math.Round(((value - Minimum) / TickFrequency)) * TickFrequency);
-                double next = Math.Min(Maximum, previous + TickFrequency);
-                value = value > (previous + next) * 0.5 ? next : previous;
+                previous = Minimum + (Math.Round((value - Minimum) / TickFrequency) * TickFrequency);
+                next = Math.Min(Maximum, previous + TickFrequency);
             }
 
-            return value;
+            // Choose the closest value between previous and next. If tie, snap to 'next'.
+            return MathUtilities.GreaterThanOrClose(value, (previous + next) * 0.5) ? next : previous;
         }
 
         private void UpdatePseudoClasses(Orientation o)

+ 416 - 0
src/Avalonia.Controls/TickBar.cs

@@ -0,0 +1,416 @@
+using System;
+using System.Collections.Generic;
+using Avalonia.Controls.Primitives;
+using Avalonia.Data;
+using Avalonia.Data.Converters;
+using Avalonia.Layout;
+using Avalonia.Media;
+using Avalonia.Utilities;
+
+namespace Avalonia.Controls
+{
+    /// <summary>
+    /// Enum which describes how to position the TickBar.
+    /// </summary>
+    public enum TickBarPlacement
+    {
+        /// <summary>
+        /// Position this tick at the left of target element.
+        /// </summary>
+        Left,
+
+        /// <summary>
+        /// Position this tick at the top of target element.
+        /// </summary>
+        Top,
+
+        /// <summary>
+        /// Position this tick at the right of target element.
+        /// </summary>
+        Right,
+
+        /// <summary>
+        /// Position this tick at the bottom of target element.
+        /// </summary>
+        Bottom,
+    }
+
+
+    /// <summary>
+    /// An element that is used for drawing <see cref="Slider"/>'s Ticks.
+    /// </summary>
+    public class TickBar : Control
+    {
+        static TickBar()
+        {
+            AffectsRender<TickBar>(ReservedSpaceProperty,
+                                   MaximumProperty,
+                                   MinimumProperty,
+                                   OrientationProperty,
+                                   TickFrequencyProperty);
+        }
+
+        public TickBar() : base()
+        {
+        }
+
+        /// <summary>
+        /// Defines the <see cref="Fill"/> property.
+        /// </summary>
+        public static readonly StyledProperty<IBrush> FillProperty =
+            AvaloniaProperty.Register<TickBar, IBrush>(nameof(Fill));
+
+        /// <summary>
+        /// Brush used to fill the TickBar's Ticks.
+        /// </summary>
+        public IBrush Fill
+        {
+            get { return GetValue(FillProperty); }
+            set { SetValue(FillProperty, value); }
+        }
+
+        /// <summary>
+        /// Defines the <see cref="Minimum"/> property.
+        /// </summary>
+        public static readonly StyledProperty<double> MinimumProperty =
+            AvaloniaProperty.Register<TickBar, double>(nameof(Minimum), 0d);
+
+        /// <summary>
+        /// Logical position where the Minimum Tick will be drawn
+        /// </summary>
+        public double Minimum
+        {
+            get { return GetValue(MinimumProperty); }
+            set
+            {
+                SetValue(MinimumProperty, value);
+            }
+        }
+
+        /// <summary>
+        /// Defines the <see cref="Maximum"/> property.
+        /// </summary>
+        public static readonly StyledProperty<double> MaximumProperty =
+            AvaloniaProperty.Register<TickBar, double>(nameof(Maximum), 0d);
+
+        /// <summary>
+        /// Logical position where the Maximum Tick will be drawn
+        /// </summary>
+        public double Maximum
+        {
+            get { return GetValue(MaximumProperty); }
+            set { SetValue(MaximumProperty, value); }
+        }
+
+        /// <summary>
+        /// Defines the <see cref="TickFrequency"/> property.
+        /// </summary>
+        public static readonly StyledProperty<double> TickFrequencyProperty =
+            AvaloniaProperty.Register<TickBar, double>(nameof(TickFrequency), 0d);
+
+        /// <summary>
+        /// TickFrequency property defines how the tick will be drawn.
+        /// </summary>
+        public double TickFrequency
+        {
+            get { return GetValue(TickFrequencyProperty); }
+            set { SetValue(TickFrequencyProperty, value); }
+        }
+
+        /// <summary>
+        /// Defines the <see cref="Orientation"/> property.
+        /// </summary>
+        public static readonly StyledProperty<Orientation> OrientationProperty =
+            AvaloniaProperty.Register<TickBar, Orientation>(nameof(Orientation));
+
+        /// <summary>
+        /// TickBar parent's orientation.
+        /// </summary>
+        public Orientation Orientation
+        {
+            get { return GetValue(OrientationProperty); }
+            set { SetValue(OrientationProperty, value); }
+        }
+
+        /// <summary>
+        /// Defines the <see cref="Ticks"/> property.
+        /// </summary>
+        public static readonly StyledProperty<List<double>> TicksProperty =
+            AvaloniaProperty.Register<TickBar, List<double>>(nameof(Ticks));
+
+        /// <summary>
+        /// The Ticks property contains collection of value of type Double which
+        /// are the logical positions use to draw the ticks.
+        /// The property value is a <see cref="DoubleCollection" />.
+        /// </summary>
+        public List<double> Ticks
+        {
+            get { return GetValue(TicksProperty); }
+            set { SetValue(TicksProperty, value); }
+        }
+
+        /// <summary>
+        /// Defines the <see cref="IsDirectionReversed"/> property.
+        /// </summary>
+        public static readonly StyledProperty<bool> IsDirectionReversedProperty =
+            AvaloniaProperty.Register<TickBar, bool>(nameof(IsDirectionReversed), false);
+
+        /// <summary>
+        /// The IsDirectionReversed property defines the direction of value incrementation.
+        /// By default, if Tick's orientation is Horizontal, ticks will be drawn from left to right.
+        /// (And, bottom to top for Vertical orientation).
+        /// If IsDirectionReversed is 'true' the direction of the drawing will be in opposite direction.
+        /// </summary>
+        public bool IsDirectionReversed
+        {
+            get { return GetValue(IsDirectionReversedProperty); }
+            set { SetValue(IsDirectionReversedProperty, value); }
+        }
+
+        /// <summary>
+        /// Defines the <see cref="Placement"/> property.
+        /// </summary>
+        public static readonly StyledProperty<TickBarPlacement> PlacementProperty =
+            AvaloniaProperty.Register<TickBar, TickBarPlacement>(nameof(Placement), 0d);
+
+
+        /// <summary>
+        /// Placement property specified how the Tick will be placed.
+        /// This property affects the way ticks are drawn.
+        /// This property has type of <see cref="TickBarPlacement" />.
+        /// </summary>
+        public TickBarPlacement Placement
+        {
+            get { return GetValue(PlacementProperty); }
+            set { SetValue(PlacementProperty, value); }
+        }
+
+        /// <summary>
+        /// Defines the <see cref="ReservedSpace"/> property.
+        /// </summary>
+        public static readonly StyledProperty<Rect> ReservedSpaceProperty =
+            AvaloniaProperty.Register<TickBar, Rect>(nameof(ReservedSpace));
+
+        /// <summary>
+        /// TickBar will use ReservedSpaceProperty for left and right spacing (for horizontal orientation) or
+        /// tob and bottom spacing (for vertical orienation).
+        /// The space on both sides of TickBar is half of specified ReservedSpace.
+        /// This property has type of <see cref="Rect" />.
+        /// </summary>
+        public Rect ReservedSpace
+        {
+            get { return GetValue(ReservedSpaceProperty); }
+            set { SetValue(ReservedSpaceProperty, value); }
+        }
+
+        /// <summary>
+        /// Draw ticks.
+        /// Ticks can be draw in 8 diffrent ways depends on Placment property and IsDirectionReversed property.
+        ///
+        /// This function also draw selection-tick(s) if IsSelectionRangeEnabled is 'true' and
+        /// SelectionStart and SelectionEnd are valid.
+        ///
+        /// The primary ticks (for Mininum and Maximum value) height will be 100% of TickBar's render size (use Width or Height
+        /// depends on Placement property).
+        ///
+        /// The secondary ticks (all other ticks, including selection-tics) height will be 75% of TickBar's render size.
+        ///
+        /// Brush that use to fill ticks is specified by Shape.Fill property.
+        ///
+        /// Pen that use to draw ticks is specified by Shape.Pen property.
+        /// </summary>
+        public override void Render(DrawingContext dc)
+        {
+            var size = new Size(Bounds.Width, Bounds.Height);
+            var range = Maximum - Minimum;
+            var tickLen = 0.0d;   // Height for Primary Tick (for Mininum and Maximum value)
+            var tickLen2 = 0.0d;  // Height for Secondary Tick
+            var logicalToPhysical = 1.0;
+            var progression = 1.0d;
+            var startPoint = new Point();
+            var endPoint = new Point();
+            var rSpace = Orientation == Orientation.Horizontal ? ReservedSpace.Width : ReservedSpace.Height;
+
+            // Take Thumb size in to account
+            double halfReservedSpace = rSpace * 0.5;
+
+            switch (Placement)
+            {
+                case TickBarPlacement.Top:
+                    if (MathUtilities.GreaterThanOrClose(rSpace, size.Width))
+                    {
+                        return;
+                    }
+                    size = new Size(size.Width - rSpace, size.Height);
+                    tickLen = -size.Height;
+                    startPoint = new Point(halfReservedSpace, size.Height);
+                    endPoint = new Point(halfReservedSpace + size.Width, size.Height);
+                    logicalToPhysical = size.Width / range;
+                    progression = 1;
+                    break;
+
+                case TickBarPlacement.Bottom:
+                    if (MathUtilities.GreaterThanOrClose(rSpace, size.Width))
+                    {
+                        return;
+                    }
+                    size = new Size(size.Width - rSpace, size.Height);
+                    tickLen = size.Height;
+                    startPoint = new Point(halfReservedSpace, 0d);
+                    endPoint = new Point(halfReservedSpace + size.Width, 0d);
+                    logicalToPhysical = size.Width / range;
+                    progression = 1;
+                    break;
+
+                case TickBarPlacement.Left:
+                    if (MathUtilities.GreaterThanOrClose(rSpace, size.Height))
+                    {
+                        return;
+                    }
+                    size = new Size(size.Width, size.Height - rSpace);
+
+                    tickLen = -size.Width;
+                    startPoint = new Point(size.Width, size.Height + halfReservedSpace);
+                    endPoint = new Point(size.Width, halfReservedSpace);
+                    logicalToPhysical = size.Height / range * -1;
+                    progression = -1;
+                    break;
+
+                case TickBarPlacement.Right:
+                    if (MathUtilities.GreaterThanOrClose(rSpace, size.Height))
+                    {
+                        return;
+                    }
+                    size = new Size(size.Width, size.Height - rSpace);
+                    tickLen = size.Width;
+                    startPoint = new Point(0d, size.Height + halfReservedSpace);
+                    endPoint = new Point(0d, halfReservedSpace);
+                    logicalToPhysical = size.Height / range * -1;
+                    progression = -1;
+                    break;
+            };
+
+            tickLen2 = tickLen * 0.75;
+
+            // Invert direciton of the ticks
+            if (IsDirectionReversed)
+            {
+                progression *= -progression;
+                logicalToPhysical *= -1;
+
+                // swap startPoint & endPoint
+                var pt = startPoint;
+                startPoint = endPoint;
+                endPoint = pt;
+            }
+
+            var pen = new Pen(Fill, 1.0d);
+
+            // Is it Vertical?
+            if (Placement == TickBarPlacement.Left || Placement == TickBarPlacement.Right)
+            {
+                // Reduce tick interval if it is more than would be visible on the screen
+                double interval = TickFrequency;
+                if (interval > 0.0)
+                {
+                    double minInterval = (Maximum - Minimum) / size.Height;
+                    if (interval < minInterval)
+                    {
+                        interval = minInterval;
+                    }
+                }
+
+                // Draw Min & Max tick
+                dc.DrawLine(pen, startPoint, new Point(startPoint.X + tickLen, startPoint.Y));
+                dc.DrawLine(pen, new Point(startPoint.X, endPoint.Y),
+                                 new Point(startPoint.X + tickLen, endPoint.Y));
+
+                // This property is rarely set so let's try to avoid the GetValue
+                // caching of the mutable default value
+                var ticks = Ticks ?? null;
+
+                // Draw ticks using specified Ticks collection
+                if (ticks?.Count > 0)
+                {
+                    for (int i = 0; i < ticks.Count; i++)
+                    {
+                        if (MathUtilities.LessThanOrClose(ticks[i], Minimum) || MathUtilities.GreaterThanOrClose(ticks[i], Maximum))
+                        {
+                            continue;
+                        }
+
+                        double adjustedTick = ticks[i] - Minimum;
+
+                        double y = adjustedTick * logicalToPhysical + startPoint.Y;
+                        dc.DrawLine(pen,
+                            new Point(startPoint.X, y),
+                            new Point(startPoint.X + tickLen2, y));
+                    }
+                }
+                // Draw ticks using specified TickFrequency
+                else if (interval > 0.0)
+                {
+                    for (double i = interval; i < range; i += interval)
+                    {
+                        double y = i * logicalToPhysical + startPoint.Y;
+
+                        dc.DrawLine(pen,
+                            new Point(startPoint.X, y),
+                            new Point(startPoint.X + tickLen2, y));
+                    }
+                }
+            }
+            else  // Placement == Top || Placement == Bottom
+            {
+                // Reduce tick interval if it is more than would be visible on the screen
+                double interval = TickFrequency;
+                if (interval > 0.0)
+                {
+                    double minInterval = (Maximum - Minimum) / size.Width;
+                    if (interval < minInterval)
+                    {
+                        interval = minInterval;
+                    }
+                }
+
+                // Draw Min & Max tick
+                dc.DrawLine(pen, startPoint, new Point(startPoint.X, startPoint.Y + tickLen));
+                dc.DrawLine(pen, new Point(endPoint.X, startPoint.Y),
+                                 new Point(endPoint.X, startPoint.Y + tickLen));
+
+                // This property is rarely set so let's try to avoid the GetValue
+                // caching of the mutable default value
+                var ticks = Ticks ?? null;
+
+                // Draw ticks using specified Ticks collection
+                if (ticks?.Count > 0)
+                {
+                    for (int i = 0; i < ticks.Count; i++)
+                    {
+                        if (MathUtilities.LessThanOrClose(ticks[i], Minimum) || MathUtilities.GreaterThanOrClose(ticks[i], Maximum))
+                        {
+                            continue;
+                        }
+                        double adjustedTick = ticks[i] - Minimum;
+
+                        double x = adjustedTick * logicalToPhysical + startPoint.X;
+                        dc.DrawLine(pen,
+                            new Point(x, startPoint.Y),
+                            new Point(x, startPoint.Y + tickLen2));
+                    }
+                }
+                // Draw ticks using specified TickFrequency
+                else if (interval > 0.0)
+                {
+                    for (double i = interval; i < range; i += interval)
+                    {
+                        double x = i * logicalToPhysical + startPoint.X;
+                        dc.DrawLine(pen,
+                            new Point(x, startPoint.Y),
+                            new Point(x, startPoint.Y + tickLen2));
+                    }
+                }
+            }
+        }
+    }
+}

+ 26 - 1
src/Avalonia.Themes.Fluent/Accents/FluentBaseDark.xaml

@@ -1,4 +1,6 @@
-<Style xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:sys="clr-namespace:System;assembly=netstandard">
+<Style xmlns="https://github.com/avaloniaui" 
+  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
+  xmlns:sys="clr-namespace:System;assembly=netstandard">
   <Style.Resources>
     <Color x:Key="SystemAccentColor">#FF0078D7</Color>
     <Color x:Key="SystemAltHighColor">#FF000000</Color>
@@ -312,5 +314,28 @@
     <StaticResource x:Key="RadioButtonCheckGlyphStrokePointerOver" ResourceKey="SystemControlTransparentBrush" />
     <StaticResource x:Key="RadioButtonCheckGlyphStrokePressed" ResourceKey="SystemControlTransparentBrush" />
     <StaticResource x:Key="RadioButtonCheckGlyphStrokeDisabled" ResourceKey="SystemControlTransparentBrush" />
+    
+    <!-- BaseResources for Slider.xaml -->
+    <StaticResource x:Key="SliderContainerBackground" ResourceKey="SystemControlTransparentBrush" />
+    <StaticResource x:Key="SliderContainerBackgroundPointerOver" ResourceKey="SystemControlTransparentBrush" />
+    <StaticResource x:Key="SliderContainerBackgroundPressed" ResourceKey="SystemControlTransparentBrush" />
+    <StaticResource x:Key="SliderContainerBackgroundDisabled" ResourceKey="SystemControlTransparentBrush" />
+    <StaticResource x:Key="SliderThumbBackground" ResourceKey="SystemControlForegroundAccentBrush" />
+    <StaticResource x:Key="SliderThumbBackgroundPointerOver" ResourceKey="SystemControlHighlightChromeAltLowBrush" />
+    <StaticResource x:Key="SliderThumbBackgroundPressed" ResourceKey="SystemControlHighlightChromeHighBrush" />
+    <StaticResource x:Key="SliderThumbBackgroundDisabled" ResourceKey="SystemControlDisabledChromeDisabledHighBrush" />
+    <StaticResource x:Key="SliderTrackFill" ResourceKey="SystemControlForegroundBaseMediumLowBrush" />
+    <StaticResource x:Key="SliderTrackFillPointerOver" ResourceKey="SystemControlForegroundBaseMediumBrush" />
+    <StaticResource x:Key="SliderTrackFillPressed" ResourceKey="SystemControlForegroundBaseMediumLowBrush" />
+    <StaticResource x:Key="SliderTrackFillDisabled" ResourceKey="SystemControlDisabledChromeDisabledHighBrush" />
+    <StaticResource x:Key="SliderTrackValueFill" ResourceKey="SystemControlHighlightAccentBrush" />
+    <StaticResource x:Key="SliderTrackValueFillPointerOver" ResourceKey="SystemControlHighlightAccentBrush" />
+    <StaticResource x:Key="SliderTrackValueFillPressed" ResourceKey="SystemControlHighlightAccentBrush" />
+    <StaticResource x:Key="SliderTrackValueFillDisabled" ResourceKey="SystemControlDisabledChromeDisabledHighBrush" />
+    <StaticResource x:Key="SliderHeaderForeground" ResourceKey="SystemControlForegroundBaseHighBrush" />
+    <StaticResource x:Key="SliderHeaderForegroundDisabled" ResourceKey="SystemControlDisabledBaseMediumLowBrush" />
+    <StaticResource x:Key="SliderTickBarFill" ResourceKey="SystemControlForegroundBaseMediumLowBrush" />
+    <StaticResource x:Key="SliderTickBarFillDisabled" ResourceKey="SystemControlDisabledBaseMediumLowBrush" />
+    <StaticResource x:Key="SliderInlineTickBarFill" ResourceKey="SystemControlBackgroundAltHighBrush" />
   </Style.Resources>
 </Style>

+ 26 - 1
src/Avalonia.Themes.Fluent/Accents/FluentBaseLight.xaml

@@ -1,4 +1,6 @@
-<Style xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:sys="clr-namespace:System;assembly=netstandard">
+<Style xmlns="https://github.com/avaloniaui" 
+  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
+  xmlns:sys="clr-namespace:System;assembly=netstandard">
   <Style.Resources>
     <Color x:Key="SystemAccentColor">#FF0078D7</Color>
     <Color x:Key="SystemAltHighColor">#FFFFFFFF</Color>
@@ -313,5 +315,28 @@
     <StaticResource x:Key="RadioButtonCheckGlyphStrokePointerOver" ResourceKey="SystemControlTransparentBrush" />
     <StaticResource x:Key="RadioButtonCheckGlyphStrokePressed" ResourceKey="SystemControlTransparentBrush" />
     <StaticResource x:Key="RadioButtonCheckGlyphStrokeDisabled" ResourceKey="SystemControlTransparentBrush" />
+    
+    <!-- BaseResources for Slider.xaml -->
+    <StaticResource x:Key="SliderContainerBackground" ResourceKey="SystemControlTransparentBrush" />
+    <StaticResource x:Key="SliderContainerBackgroundPointerOver" ResourceKey="SystemControlTransparentBrush" />
+    <StaticResource x:Key="SliderContainerBackgroundPressed" ResourceKey="SystemControlTransparentBrush" />
+    <StaticResource x:Key="SliderContainerBackgroundDisabled" ResourceKey="SystemControlTransparentBrush" />
+    <StaticResource x:Key="SliderThumbBackground" ResourceKey="SystemControlForegroundAccentBrush" />
+    <StaticResource x:Key="SliderThumbBackgroundPointerOver" ResourceKey="SystemControlHighlightChromeAltLowBrush" />
+    <StaticResource x:Key="SliderThumbBackgroundPressed" ResourceKey="SystemControlHighlightChromeHighBrush" />
+    <StaticResource x:Key="SliderThumbBackgroundDisabled" ResourceKey="SystemControlDisabledChromeDisabledHighBrush" />
+    <StaticResource x:Key="SliderTrackFill" ResourceKey="SystemControlForegroundBaseMediumLowBrush" />
+    <StaticResource x:Key="SliderTrackFillPointerOver" ResourceKey="SystemControlForegroundBaseMediumBrush" />
+    <StaticResource x:Key="SliderTrackFillPressed" ResourceKey="SystemControlForegroundBaseMediumLowBrush" />
+    <StaticResource x:Key="SliderTrackFillDisabled" ResourceKey="SystemControlDisabledChromeDisabledHighBrush" />
+    <StaticResource x:Key="SliderTrackValueFill" ResourceKey="SystemControlHighlightAccentBrush" />
+    <StaticResource x:Key="SliderTrackValueFillPointerOver" ResourceKey="SystemControlHighlightAccentBrush" />
+    <StaticResource x:Key="SliderTrackValueFillPressed" ResourceKey="SystemControlHighlightAccentBrush" />
+    <StaticResource x:Key="SliderTrackValueFillDisabled" ResourceKey="SystemControlDisabledChromeDisabledHighBrush" />
+    <StaticResource x:Key="SliderHeaderForeground" ResourceKey="SystemControlForegroundBaseHighBrush" />
+    <StaticResource x:Key="SliderHeaderForegroundDisabled" ResourceKey="SystemControlDisabledBaseMediumLowBrush" />
+    <StaticResource x:Key="SliderTickBarFill" ResourceKey="SystemControlForegroundBaseMediumLowBrush" />
+    <StaticResource x:Key="SliderTickBarFillDisabled" ResourceKey="SystemControlDisabledBaseMediumLowBrush" />
+    <StaticResource x:Key="SliderInlineTickBarFill" ResourceKey="SystemControlBackgroundAltHighBrush" />
   </Style.Resources>
 </Style>

+ 53 - 3
src/Avalonia.Themes.Fluent/Accents/FluentControlResourcesDark.xaml

@@ -1,6 +1,6 @@
-<Style xmlns="https://github.com/avaloniaui"
-       xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
-       xmlns:sys="clr-namespace:System;assembly=netstandard">
+<Style xmlns="https://github.com/avaloniaui" 
+  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
+  xmlns:sys="clr-namespace:System;assembly=netstandard">
   <Style.Resources>
     <!-- Resources for Button.xaml -->
     <StaticResource x:Key="AccentButtonBackground" ResourceKey="SystemControlBackgroundAccentBrush" />
@@ -343,5 +343,55 @@
     <SolidColorBrush x:Key="RadioButtonPressedBorderThemeBrush" Color="#FFFFFFFF" />
     <SolidColorBrush x:Key="RadioButtonPressedForegroundThemeBrush" Color="#FF000000" />
     <SolidColorBrush x:Key="RadioButtonContentPointerOverForegroundThemeBrush" Color="{DynamicResource SystemColorHighlightTextColor}" />
+    
+    <!-- Resources for Slider.xaml -->
+    <x:Double x:Key="SliderOutsideTickBarThemeHeight">4</x:Double>
+    <x:Double x:Key="SliderTrackThemeHeight">2</x:Double>
+    <Thickness x:Key="SliderBorderThemeThickness">0</Thickness>
+    <Thickness x:Key="SliderHeaderThemeMargin">0,0,0,4</Thickness>
+    <FontWeight x:Key="SliderHeaderThemeFontWeight">Normal</FontWeight>
+    <StaticResource x:Key="SliderContainerBackground" ResourceKey="SystemControlTransparentBrush" />
+    <StaticResource x:Key="SliderContainerBackgroundPointerOver" ResourceKey="SystemControlTransparentBrush" />
+    <StaticResource x:Key="SliderContainerBackgroundPressed" ResourceKey="SystemControlTransparentBrush" />
+    <StaticResource x:Key="SliderContainerBackgroundDisabled" ResourceKey="SystemControlTransparentBrush" />
+    <StaticResource x:Key="SliderThumbBackground" ResourceKey="SystemControlForegroundAccentBrush" />
+    <StaticResource x:Key="SliderThumbBackgroundPointerOver" ResourceKey="SystemAccentColorLight1" />
+    <StaticResource x:Key="SliderThumbBackgroundPressed" ResourceKey="SystemAccentColorDark1" />
+    <StaticResource x:Key="SliderThumbBackgroundDisabled" ResourceKey="SystemControlDisabledChromeDisabledHighBrush" />
+    <StaticResource x:Key="SliderTrackFill" ResourceKey="SystemControlForegroundBaseMediumLowBrush" />
+    <StaticResource x:Key="SliderTrackFillPointerOver" ResourceKey="SystemControlForegroundBaseMediumBrush" />
+    <StaticResource x:Key="SliderTrackFillPressed" ResourceKey="SystemControlForegroundBaseMediumLowBrush" />
+    <StaticResource x:Key="SliderTrackFillDisabled" ResourceKey="SystemControlDisabledChromeDisabledHighBrush" />
+    <StaticResource x:Key="SliderTrackValueFill" ResourceKey="SystemControlHighlightAccentBrush" />
+    <StaticResource x:Key="SliderTrackValueFillPointerOver" ResourceKey="SystemControlHighlightAccentBrush" />
+    <StaticResource x:Key="SliderTrackValueFillPressed" ResourceKey="SystemControlHighlightAccentBrush" />
+    <StaticResource x:Key="SliderTrackValueFillDisabled" ResourceKey="SystemControlDisabledChromeDisabledHighBrush" />
+    <StaticResource x:Key="SliderHeaderForeground" ResourceKey="SystemControlForegroundBaseHighBrush" />
+    <StaticResource x:Key="SliderHeaderForegroundDisabled" ResourceKey="SystemControlDisabledBaseMediumLowBrush" />
+    <StaticResource x:Key="SliderTickBarFill" ResourceKey="SystemControlForegroundBaseMediumLowBrush" />
+    <StaticResource x:Key="SliderTickBarFillDisabled" ResourceKey="SystemControlDisabledBaseMediumLowBrush" />
+    <StaticResource x:Key="SliderInlineTickBarFill" ResourceKey="SystemControlBackgroundAltHighBrush" />
+    <SolidColorBrush x:Key="SliderBorderThemeBrush" Color="Transparent" />
+    <SolidColorBrush x:Key="SliderDisabledBorderThemeBrush" Color="Transparent" />
+    <SolidColorBrush x:Key="SliderThumbBackgroundThemeBrush" Color="#FFFFFFFF" />
+    <SolidColorBrush x:Key="SliderThumbBorderThemeBrush" Color="#FFFFFFFF" />
+    <SolidColorBrush x:Key="SliderThumbDisabledBackgroundThemeBrush" Color="#FF7E7E7E" />
+    <SolidColorBrush x:Key="SliderThumbPointerOverBackgroundThemeBrush" Color="#FFFFFFFF" />
+    <SolidColorBrush x:Key="SliderThumbPointerOverBorderThemeBrush" Color="#FFFFFFFF" />
+    <SolidColorBrush x:Key="SliderThumbPressedBackgroundThemeBrush" Color="#FFFFFFFF" />
+    <SolidColorBrush x:Key="SliderThumbPressedBorderThemeBrush" Color="#FFFFFFFF" />
+    <SolidColorBrush x:Key="SliderTickMarkInlineBackgroundThemeBrush" Color="Black" />
+    <SolidColorBrush x:Key="SliderTickMarkInlineDisabledForegroundThemeBrush" Color="Black" />
+    <SolidColorBrush x:Key="SliderTickmarkOutsideBackgroundThemeBrush" Color="#80FFFFFF" />
+    <SolidColorBrush x:Key="SliderTickMarkOutsideDisabledForegroundThemeBrush" Color="#80FFFFFF" />
+    <SolidColorBrush x:Key="SliderTrackBackgroundThemeBrush" Color="#29FFFFFF" />
+    <SolidColorBrush x:Key="SliderTrackDecreaseBackgroundThemeBrush" Color="#FF5B2EC5" />
+    <SolidColorBrush x:Key="SliderTrackDecreaseDisabledBackgroundThemeBrush" Color="#1FFFFFFF" />
+    <SolidColorBrush x:Key="SliderTrackDecreasePointerOverBackgroundThemeBrush" Color="#FF724BCD" />
+    <SolidColorBrush x:Key="SliderTrackDecreasePressedBackgroundThemeBrush" Color="#FF8152EF" />
+    <SolidColorBrush x:Key="SliderTrackDisabledBackgroundThemeBrush" Color="#29FFFFFF" />
+    <SolidColorBrush x:Key="SliderTrackPointerOverBackgroundThemeBrush" Color="#46FFFFFF" />
+    <SolidColorBrush x:Key="SliderTrackPressedBackgroundThemeBrush" Color="#59FFFFFF" />
+    <SolidColorBrush x:Key="SliderHeaderForegroundThemeBrush" Color="#FFFFFFFF" />
   </Style.Resources>
 </Style>

+ 53 - 3
src/Avalonia.Themes.Fluent/Accents/FluentControlResourcesLight.xaml

@@ -1,6 +1,6 @@
-<Style xmlns="https://github.com/avaloniaui"
-       xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
-       xmlns:sys="clr-namespace:System;assembly=netstandard">
+<Style xmlns="https://github.com/avaloniaui" 
+  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
+  xmlns:sys="clr-namespace:System;assembly=netstandard">
   <Style.Resources>
     <!-- Resources for Button.xaml -->
     <StaticResource x:Key="AccentButtonBackground" ResourceKey="SystemControlBackgroundAccentBrush" />
@@ -343,5 +343,55 @@
     <SolidColorBrush x:Key="RadioButtonPressedBorderThemeBrush" Color="#FF000000" />
     <SolidColorBrush x:Key="RadioButtonPressedForegroundThemeBrush" Color="#FFFFFFFF" />
     <SolidColorBrush x:Key="RadioButtonContentPointerOverForegroundThemeBrush" Color="{DynamicResource SystemColorHighlightTextColor}" />
+    
+    <!-- Resources for Slider.xaml -->
+    <x:Double x:Key="SliderOutsideTickBarThemeHeight">4</x:Double>
+    <x:Double x:Key="SliderTrackThemeHeight">2</x:Double>
+    <Thickness x:Key="SliderBorderThemeThickness">0</Thickness>
+    <Thickness x:Key="SliderHeaderThemeMargin">0,0,0,4</Thickness>
+    <FontWeight x:Key="SliderHeaderThemeFontWeight">Normal</FontWeight>
+    <StaticResource x:Key="SliderContainerBackground" ResourceKey="SystemControlTransparentBrush" />
+    <StaticResource x:Key="SliderContainerBackgroundPointerOver" ResourceKey="SystemControlTransparentBrush" />
+    <StaticResource x:Key="SliderContainerBackgroundPressed" ResourceKey="SystemControlTransparentBrush" />
+    <StaticResource x:Key="SliderContainerBackgroundDisabled" ResourceKey="SystemControlTransparentBrush" />
+    <StaticResource x:Key="SliderThumbBackground" ResourceKey="SystemControlForegroundAccentBrush" />
+    <StaticResource x:Key="SliderThumbBackgroundPointerOver" ResourceKey="SystemAccentColorLight1" />
+    <StaticResource x:Key="SliderThumbBackgroundPressed" ResourceKey="SystemAccentColorDark1" />
+    <StaticResource x:Key="SliderThumbBackgroundDisabled" ResourceKey="SystemControlDisabledChromeDisabledHighBrush" />
+    <StaticResource x:Key="SliderTrackFill" ResourceKey="SystemControlForegroundBaseMediumLowBrush" />
+    <StaticResource x:Key="SliderTrackFillPointerOver" ResourceKey="SystemControlForegroundBaseMediumBrush" />
+    <StaticResource x:Key="SliderTrackFillPressed" ResourceKey="SystemControlForegroundBaseMediumLowBrush" />
+    <StaticResource x:Key="SliderTrackFillDisabled" ResourceKey="SystemControlDisabledChromeDisabledHighBrush" />
+    <StaticResource x:Key="SliderTrackValueFill" ResourceKey="SystemControlHighlightAccentBrush" />
+    <StaticResource x:Key="SliderTrackValueFillPointerOver" ResourceKey="SystemControlHighlightAccentBrush" />
+    <StaticResource x:Key="SliderTrackValueFillPressed" ResourceKey="SystemControlHighlightAccentBrush" />
+    <StaticResource x:Key="SliderTrackValueFillDisabled" ResourceKey="SystemControlDisabledChromeDisabledHighBrush" />
+    <StaticResource x:Key="SliderHeaderForeground" ResourceKey="SystemControlForegroundBaseHighBrush" />
+    <StaticResource x:Key="SliderHeaderForegroundDisabled" ResourceKey="SystemControlDisabledBaseMediumLowBrush" />
+    <StaticResource x:Key="SliderTickBarFill" ResourceKey="SystemControlForegroundBaseMediumLowBrush" />
+    <StaticResource x:Key="SliderTickBarFillDisabled" ResourceKey="SystemControlDisabledBaseMediumLowBrush" />
+    <StaticResource x:Key="SliderInlineTickBarFill" ResourceKey="SystemControlBackgroundAltHighBrush" />
+    <SolidColorBrush x:Key="SliderBorderThemeBrush" Color="Transparent" />
+    <SolidColorBrush x:Key="SliderDisabledBorderThemeBrush" Color="Transparent" />
+    <SolidColorBrush x:Key="SliderThumbBackgroundThemeBrush" Color="#FF000000" />
+    <SolidColorBrush x:Key="SliderThumbBorderThemeBrush" Color="#FF000000" />
+    <SolidColorBrush x:Key="SliderThumbDisabledBackgroundThemeBrush" Color="#FF929292" />
+    <SolidColorBrush x:Key="SliderThumbPointerOverBackgroundThemeBrush" Color="#FF000000" />
+    <SolidColorBrush x:Key="SliderThumbPointerOverBorderThemeBrush" Color="#FF000000" />
+    <SolidColorBrush x:Key="SliderThumbPressedBackgroundThemeBrush" Color="#FF000000" />
+    <SolidColorBrush x:Key="SliderThumbPressedBorderThemeBrush" Color="#FF000000" />
+    <SolidColorBrush x:Key="SliderTickMarkInlineBackgroundThemeBrush" Color="White" />
+    <SolidColorBrush x:Key="SliderTickMarkInlineDisabledForegroundThemeBrush" Color="White" />
+    <SolidColorBrush x:Key="SliderTickmarkOutsideBackgroundThemeBrush" Color="#80000000" />
+    <SolidColorBrush x:Key="SliderTickMarkOutsideDisabledForegroundThemeBrush" Color="#80000000" />
+    <SolidColorBrush x:Key="SliderTrackBackgroundThemeBrush" Color="#1A000000" />
+    <SolidColorBrush x:Key="SliderTrackDecreaseBackgroundThemeBrush" Color="#FF4617B4" />
+    <SolidColorBrush x:Key="SliderTrackDecreaseDisabledBackgroundThemeBrush" Color="#1C000000" />
+    <SolidColorBrush x:Key="SliderTrackDecreasePointerOverBackgroundThemeBrush" Color="#FF5F37BE" />
+    <SolidColorBrush x:Key="SliderTrackDecreasePressedBackgroundThemeBrush" Color="#FF7241E4" />
+    <SolidColorBrush x:Key="SliderTrackDisabledBackgroundThemeBrush" Color="#1A000000" />
+    <SolidColorBrush x:Key="SliderTrackPointerOverBackgroundThemeBrush" Color="#26000000" />
+    <SolidColorBrush x:Key="SliderTrackPressedBackgroundThemeBrush" Color="#33000000" />
+    <SolidColorBrush x:Key="SliderHeaderForegroundThemeBrush" Color="#FF000000" />
   </Style.Resources>
 </Style>

+ 247 - 76
src/Avalonia.Themes.Fluent/Slider.xaml

@@ -1,93 +1,264 @@
-<Styles xmlns="https://github.com/avaloniaui">
+<Styles xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
+  <Design.PreviewWith>
+    <Border Margin="20" Width="200" Height="200">
+      <DockPanel LastChildFill="True">
+        <StackPanel Spacing="10" DockPanel.Dock="Top">
+          <Slider Value="50" />
+          <Slider IsEnabled="False" Value="50" />
+        </StackPanel>
+        <StackPanel Spacing="10" Orientation="Horizontal">
+          <Slider Value="50" Orientation="Vertical" />
+          <Slider IsEnabled="False" Orientation="Vertical" Value="50" />
+        </StackPanel>
+      </DockPanel>
+    </Border>
+  </Design.PreviewWith>
+  <Styles.Resources>
+    <Thickness x:Key="SliderTopHeaderMargin">0,0,0,4</Thickness>
+    <GridLength x:Key="SliderPreContentMargin">15</GridLength>
+    <GridLength x:Key="SliderPostContentMargin">15</GridLength>
+    <x:Double x:Key="SliderHorizontalHeight">32</x:Double>
+    <x:Double x:Key="SliderVerticalWidth">32</x:Double>
+    <CornerRadius x:Key="SliderThumbCornerRadius">10</CornerRadius>
+    <x:Double x:Key="SliderHorizontalThumbWidth">20</x:Double>
+    <x:Double x:Key="SliderHorizontalThumbHeight">20</x:Double>
+    <x:Double x:Key="SliderVerticalThumbWidth">20</x:Double>
+    <x:Double x:Key="SliderVerticalThumbHeight">20</x:Double>
+  </Styles.Resources>
+  <Style Selector="Thumb.SliderThumbStyle">
+    <Setter Property="BorderThickness" Value="0" />
+    <Setter Property="Template">
+      <Setter.Value>
+        <ControlTemplate>
+          <Border Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" CornerRadius="{DynamicResource SliderThumbCornerRadius}" />
+        </ControlTemplate>
+      </Setter.Value>
+    </Setter>
+  </Style>
   <Style Selector="Slider:horizontal">
-    <Setter Property="MinWidth" Value="40"/>
-    <Setter Property="MinHeight" Value="20"/>
+    <Setter Property="Background" Value="{DynamicResource SliderTrackFill}" />
+    <Setter Property="BorderThickness" Value="{DynamicResource SliderBorderThemeThickness}" />
+    <Setter Property="Foreground" Value="{DynamicResource SliderTrackValueFill}" />
+    <Setter Property="FontFamily" Value="{DynamicResource ContentControlThemeFontFamily}" />
+    <Setter Property="FontSize" Value="{DynamicResource ControlContentThemeFontSize}" />
     <Setter Property="Template">
       <ControlTemplate>
-        <Grid Name="grid">
-          <Grid.RowDefinitions>
-            <RowDefinition Height="Auto"/>
-            <RowDefinition Height="Auto" MinHeight="20"/>
-            <RowDefinition Height="Auto"/>
-          </Grid.RowDefinitions>
-          <Border Name="TrackBackground" Grid.Row="1" Height="4" Margin="6,0" VerticalAlignment="Center"/>
-          <Track Name="PART_Track" Grid.Row="1" Orientation="Horizontal">
-            <Track.DecreaseButton>
-               <RepeatButton Name="PART_DecreaseButton"
-                             Classes="repeattrack" />
-            </Track.DecreaseButton>
-            <Track.IncreaseButton>
-               <RepeatButton Name="PART_IncreaseButton"
-                             Classes="repeattrack" />
-            </Track.IncreaseButton>
-            <Thumb Name="thumb" MinWidth="20" MinHeight="20">
-              <Thumb.Template>
-                <ControlTemplate>
-                  <Grid>
-                    <Ellipse Width="12" Height="12" Fill="{DynamicResource ThemeAccentBrush}"/>
-                  </Grid>
-                </ControlTemplate>
-              </Thumb.Template>
-            </Thumb>
-          </Track>
-        </Grid>
+        <Border BorderThickness="{TemplateBinding BorderThickness}" BorderBrush="{TemplateBinding BorderBrush}" CornerRadius="{DynamicResource ControlCornerRadius}">
+          <Grid Name="grid" Margin="{TemplateBinding Padding}" RowDefinitions="Auto, *">
+            <ContentPresenter x:Name="HeaderContentPresenter" Grid.Row="0" TextBlock.FontWeight="{DynamicResource SliderHeaderThemeFontWeight}" TextBlock.Foreground="{DynamicResource SliderHeaderForeground}"
+            Margin="{DynamicResource SliderTopHeaderMargin}" />
+            <Grid x:Name="SliderContainer" Grid.Row="1">
+              <Grid.Styles>
+                <Style Selector="TickBar">
+                  <Setter Property="ReservedSpace" Value="{Binding #PART_Track.Thumb.Bounds}" />
+                </Style>
+              </Grid.Styles>
+              <Grid x:Name="HorizontalTemplate" ColumnDefinitions="Auto,Auto,*" MinHeight="{DynamicResource SliderHorizontalHeight}">
+                <Grid.RowDefinitions>
+                  <RowDefinition Height="{DynamicResource SliderPreContentMargin}" />
+                  <RowDefinition Height="Auto" />
+                  <RowDefinition Height="{DynamicResource SliderPostContentMargin}" />
+                </Grid.RowDefinitions>
+                <TickBar Name="TopTickBar" Placement="Top" Height="{DynamicResource SliderOutsideTickBarThemeHeight}" VerticalAlignment="Bottom" Margin="0,0,0,4" Grid.ColumnSpan="3" />
+                <!-- <TickBar Name="HorizontalInlineTickBar" Placement="Top" Fill="{DynamicResource SliderInlineTickBarFill}" Height="{DynamicResource SliderTrackThemeHeight}" Grid.Row="1" Grid.ColumnSpan="3" /> -->
+                <TickBar Name="BottomTickBar" Placement="Bottom" Height="{DynamicResource SliderOutsideTickBarThemeHeight}" VerticalAlignment="Top" Margin="0,4,0,0" Grid.Row="2" Grid.ColumnSpan="3" />
+                <Track Name="PART_Track" Grid.Row="1" Grid.ColumnSpan="3" Orientation="Horizontal">
+                  <Track.DecreaseButton>
+                    <RepeatButton Name="PART_DecreaseButton" Background="{TemplateBinding Foreground}">
+                      <RepeatButton.Template>
+                        <ControlTemplate>
+                          <Grid>
+                            <Border Name="FocusTarget" Background="Transparent" Margin="0,-10" />
+                            <Border Name="TrackBackground" Background="{TemplateBinding Background}" CornerRadius="{DynamicResource ControlCornerRadius}" Height="{DynamicResource SliderTrackThemeHeight}" VerticalAlignment="Center" />
+                          </Grid>
+                        </ControlTemplate>
+                      </RepeatButton.Template>
+                    </RepeatButton>
+                  </Track.DecreaseButton>
+                  <Track.IncreaseButton>
+                    <RepeatButton Name="PART_IncreaseButton" Background="{TemplateBinding Background}">
+                      <RepeatButton.Template>
+                        <ControlTemplate>
+                          <Grid>
+                            <Border Name="FocusTarget" Background="Transparent" Margin="0,-10" />
+                            <Border Name="TrackBackground" Background="{TemplateBinding Background}" CornerRadius="{DynamicResource ControlCornerRadius}" Height="{DynamicResource SliderTrackThemeHeight}" VerticalAlignment="Center" />
+                          </Grid>
+                        </ControlTemplate>
+                      </RepeatButton.Template>
+                    </RepeatButton>
+                  </Track.IncreaseButton>
+                  <Thumb Classes="SliderThumbStyle" Name="thumb" Margin="0" Padding="0" DataContext="{TemplateBinding Value}" Height="{DynamicResource SliderHorizontalThumbHeight}" Width="{DynamicResource SliderHorizontalThumbWidth}" />
+                </Track>
+              </Grid>
+            </Grid>
+          </Grid>
+        </Border>
       </ControlTemplate>
     </Setter>
   </Style>
   <Style Selector="Slider:vertical">
-    <Setter Property="MinWidth" Value="20"/>
-    <Setter Property="MinHeight" Value="40"/>
+    <Setter Property="Background" Value="{DynamicResource SliderTrackFill}" />
+    <Setter Property="BorderThickness" Value="{DynamicResource SliderBorderThemeThickness}" />
+    <Setter Property="Foreground" Value="{DynamicResource SliderTrackValueFill}" />
+    <Setter Property="FontFamily" Value="{DynamicResource ContentControlThemeFontFamily}" />
+    <Setter Property="FontSize" Value="{DynamicResource ControlContentThemeFontSize}" />
     <Setter Property="Template">
       <ControlTemplate>
-        <Grid>
-          <Grid.ColumnDefinitions>
-            <ColumnDefinition Width="Auto"/>
-            <ColumnDefinition Width="Auto" MinWidth="26"/>
-            <ColumnDefinition Width="Auto"/>
-          </Grid.ColumnDefinitions>
-          <Border Name="TrackBackground" Grid.Column="1" Width="4" Margin="0,6" HorizontalAlignment="Center"/>
-          <Track Name="PART_Track" Grid.Column="1" Orientation="Vertical" IsDirectionReversed="True">
-            <Track.DecreaseButton>
-               <RepeatButton Name="PART_DecreaseButton"
-                             Classes="repeattrack" />
-            </Track.DecreaseButton>
-            <Track.IncreaseButton>
-               <RepeatButton Name="PART_IncreaseButton"
-                             Classes="repeattrack" />
-            </Track.IncreaseButton>
-            <Thumb Name="thumb" MinWidth="20" MinHeight="20">
-              <Thumb.Template>
-                <ControlTemplate>
-                  <Grid>
-                    <Ellipse Width="12" Height="12" Fill="{DynamicResource ThemeAccentBrush}"/>
-                  </Grid>
-                </ControlTemplate>
-              </Thumb.Template>
-            </Thumb>
-          </Track>
-        </Grid>
+        <Border BorderThickness="{TemplateBinding BorderThickness}" BorderBrush="{TemplateBinding BorderBrush}" CornerRadius="{DynamicResource ControlCornerRadius}">
+          <Grid Name="grid" Margin="{TemplateBinding Padding}" RowDefinitions="Auto, *">
+            <ContentPresenter x:Name="HeaderContentPresenter" Grid.Row="0" TextBlock.FontWeight="{DynamicResource SliderHeaderThemeFontWeight}" TextBlock.Foreground="{DynamicResource SliderHeaderForeground}"
+            Margin="{DynamicResource SliderTopHeaderMargin}" />
+            <Grid x:Name="SliderContainer" Grid.Row="1">
+              <Grid.Styles>
+                <Style Selector="TickBar">
+                  <Setter Property="ReservedSpace" Value="{Binding #PART_Track.Thumb.Bounds}" />
+                </Style>
+              </Grid.Styles>
+              <Grid x:Name="VerticalTemplate" RowDefinitions="*,Auto,Auto" MinWidth="{DynamicResource SliderVerticalWidth}">
+                <Grid.ColumnDefinitions>
+                  <ColumnDefinition Width="{DynamicResource SliderPreContentMargin}" />
+                  <ColumnDefinition Width="Auto" />
+                  <ColumnDefinition Width="{DynamicResource SliderPostContentMargin}" />
+                </Grid.ColumnDefinitions>
+                <TickBar Name="LeftTickBar" Placement="Left" Width="{DynamicResource SliderOutsideTickBarThemeHeight}" HorizontalAlignment="Right" Margin="0,0,4,0" Grid.RowSpan="3" />
+                <!-- <TickBar Name="VerticalInlineTickBar" Placement="Inline" Fill="{DynamicResource SliderInlineTickBarFill}" Width="{DynamicResource SliderTrackThemeHeight}" Grid.Column="1" Grid.RowSpan="3" /> -->
+                <TickBar Name="RightTickBar" Placement="Right" Width="{DynamicResource SliderOutsideTickBarThemeHeight}" HorizontalAlignment="Left" Margin="4,0,0,0" Grid.Column="2" Grid.RowSpan="3" />
+                <Track Name="PART_Track" Grid.Column="1" Grid.ColumnSpan="1" Grid.RowSpan="3" Orientation="Vertical">
+                  <Track.DecreaseButton>
+                    <RepeatButton Name="PART_DecreaseButton" Background="{TemplateBinding Foreground}">
+                      <RepeatButton.Template>
+                        <ControlTemplate>
+                          <Grid>
+                            <Border Name="FocusTarget" Background="Transparent" Margin="0,-10" />
+                            <Border Name="TrackBackground" Background="{TemplateBinding Background}" CornerRadius="{DynamicResource ControlCornerRadius}" Width="{DynamicResource SliderTrackThemeHeight}" HorizontalAlignment="Center" />
+                          </Grid>
+                        </ControlTemplate>
+                      </RepeatButton.Template>
+                    </RepeatButton>
+                  </Track.DecreaseButton>
+                  <Track.IncreaseButton>
+                    <RepeatButton Name="PART_IncreaseButton" Background="{TemplateBinding Background}">
+                      <RepeatButton.Template>
+                        <ControlTemplate>
+                          <Grid>
+                            <Border Name="FocusTarget" Background="Transparent" Margin="0,-10" />
+                            <Border Name="TrackBackground" Background="{TemplateBinding Background}" CornerRadius="{DynamicResource ControlCornerRadius}" Width="{DynamicResource SliderTrackThemeHeight}" HorizontalAlignment="Center" />
+                          </Grid>
+                        </ControlTemplate>
+                      </RepeatButton.Template>
+                    </RepeatButton>
+                  </Track.IncreaseButton>
+                  <Thumb Classes="SliderThumbStyle" Name="SliderThumb" Margin="0" Padding="0" DataContext="{TemplateBinding Value}" Height="{DynamicResource SliderVerticalThumbHeight}" Width="{DynamicResource SliderVerticalThumbWidth}" />
+                </Track>
+              </Grid>
+            </Grid>
+          </Grid>
+        </Border>
       </ControlTemplate>
     </Setter>
   </Style>
   <Style Selector="Slider /template/ Track#PART_Track">
-    <Setter Property="Minimum" Value="{TemplateBinding Minimum}"/>
-    <Setter Property="Maximum" Value="{TemplateBinding Maximum}"/>
-    <Setter Property="Value" Value="{TemplateBinding Value, Mode=TwoWay}"/>
+    <Setter Property="Minimum" Value="{TemplateBinding Minimum}" />
+    <Setter Property="Maximum" Value="{TemplateBinding Maximum}" />
+    <Setter Property="Value" Value="{TemplateBinding Value, Mode=TwoWay}" />
   </Style>
-  <Style Selector="Slider /template/ Border#TrackBackground">
-    <Setter Property="BorderThickness" Value="2"/>
-    <Setter Property="BorderBrush" Value="{DynamicResource ThemeBorderLowBrush}"/>
+  <Style Selector="Slider /template/ TickBar">
+    <Setter Property="Fill" Value="{DynamicResource SliderTickBarFill}" />
+    <Setter Property="TickFrequency" Value="{TemplateBinding Slider.TickFrequency}" />
+    <Setter Property="Orientation" Value="{TemplateBinding Slider.Orientation}" />
+    <Setter Property="Minimum" Value="{TemplateBinding Slider.Minimum}" />
+    <Setter Property="Maximum" Value="{TemplateBinding Slider.Maximum}" />
   </Style>
-  <Style Selector="Slider /template/ RepeatButton.repeattrack">
-    <Setter Property="Background" Value="Transparent"/>
-    <Setter Property="Foreground" Value="{DynamicResource ThemeBorderLowBrush}"/>
-    <Setter Property="Template">
-        <ControlTemplate>
-            <Border Background="{TemplateBinding Background}" />
-        </ControlTemplate>
-    </Setter>
+  
+  <!-- Normal State -->
+  
+  <Style Selector="Slider /template/ Thumb.SliderThumbStyle">
+    <Setter Property="Background" Value="{DynamicResource SliderThumbBackground}" />
+  </Style>
+
+  <Style Selector="Slider /template/ Grid#SliderContainer">
+    <Setter Property="Background" Value="{DynamicResource SliderContainerBackground}" />
+  </Style>
+
+  <Style Selector="Slider /template/ TickBar">
+    <Setter Property="IsVisible" Value="False" />
+  </Style>
+
+  <!-- TickBar Placement States -->
+
+  <Style Selector="Slider[TickPlacement=TopLeft] /template/ TickBar#LeftTickBar, Slider[TickPlacement=Outside] /template/ TickBar#LeftTickBar">
+    <Setter Property="IsVisible" Value="True" />
+  </Style>
+ 
+  <Style Selector="Slider[TickPlacement=TopLeft] /template/ TickBar#TopTickBar, Slider[TickPlacement=Outside] /template/ TickBar#TopTickBar">
+    <Setter Property="IsVisible" Value="True" />
+  </Style>
+ 
+  <Style Selector="Slider[TickPlacement=BottomRight] /template/ TickBar#BottomTickBar, Slider[TickPlacement=Outside] /template/ TickBar#BottomTickBar">
+    <Setter Property="IsVisible" Value="True" />
+  </Style>
+ 
+  <Style Selector="Slider[TickPlacement=BottomRight] /template/ TickBar#RightTickBar, Slider[TickPlacement=Outside] /template/ TickBar#RightTickBar">
+    <Setter Property="IsVisible" Value="True" />
+  </Style>
+ 
+  <!-- Disabled State -->
+
+  <Style Selector="Slider:disabled /template/ ContentPresenter#HeaderContentPresenter">
+    <Setter Property="TextBlock.Foreground" Value="{DynamicResource SliderHeaderForegroundDisabled}" />
+  </Style>
+  
+  <Style Selector="Slider:disabled /template/ RepeatButton#PART_DecreaseButton">
+    <Setter Property="Background" Value="{DynamicResource SliderTrackValueFillDisabled}" />
+  </Style>
+  
+  <Style Selector="Slider:disabled /template/ RepeatButton#PART_IncreaseButton">
+    <Setter Property="Background" Value="{DynamicResource SliderTrackFillDisabled}" />
+  </Style>
+  
+  <Style Selector="Slider:disabled /template/ Thumb.SliderThumbStyle">
+    <Setter Property="Background" Value="{DynamicResource SliderThumbBackgroundDisabled}" />
+  </Style>
+  
+  <Style Selector="Slider:disabled /template/ TickBar">
+    <Setter Property="Fill" Value="{DynamicResource SliderTickBarFillDisabled}" />
+  </Style>
+  
+  <Style Selector="Slider:pointerover /template/ Grid#SliderContainer">
+    <Setter Property="Background" Value="{DynamicResource SliderContainerBackgroundDisabled}" />
+  </Style>
+
+  <!-- PointerOver State -->
+  <Style Selector="Slider:pointerover /template/ RepeatButton#PART_IncreaseButton">
+    <Setter Property="Background" Value="{DynamicResource SliderTrackFillPointerOver}" />
+  </Style>
+  
+  <Style Selector="Slider:pointerover /template/ Thumb.SliderThumbStyle">
+    <Setter Property="Background" Value="{DynamicResource SliderThumbBackgroundPointerOver}" />
+  </Style>
+  
+  <Style Selector="Slider:pointerover /template/ Grid#SliderContainer">
+    <Setter Property="Background" Value="{DynamicResource SliderContainerBackgroundPointerOver}" />
+  </Style>
+  
+  <Style Selector="Slider:pointerover /template/ RepeatButton#PART_DecreaseButton">
+    <Setter Property="Background" Value="{DynamicResource SliderTrackValueFillPointerOver}" />
+  </Style>
+
+  <!-- Pressed State -->
+  <Style Selector="Slider:pressed /template/ RepeatButton#PART_IncreaseButton">
+    <Setter Property="Background" Value="{DynamicResource SliderTrackFillPressed}" />
+  </Style>
+
+  <Style Selector="Slider:pressed /template/ Thumb.SliderThumbStyle">
+    <Setter Property="Background" Value="{DynamicResource SliderThumbBackgroundPressed}" />
+  </Style>
+  
+  <Style Selector="Slider:pointerover /template/ Grid#SliderContainer">
+    <Setter Property="Background" Value="{DynamicResource SliderContainerBackgroundPressed}" />
+  </Style>
+  
+  <Style Selector="Slider:pointerover /template/ RepeatButton#PART_DecreaseButton">
+    <Setter Property="Background" Value="{DynamicResource SliderTrackValueFillPressed}" />
   </Style>
-    <Style Selector="Slider:disabled /template/ Grid#grid">
-        <Setter Property="Opacity" Value="{DynamicResource ThemeDisabledOpacity}" />
-    </Style>
 </Styles>