diff --git a/components/RangeSelector/samples/RangeSelector.md b/components/RangeSelector/samples/RangeSelector.md
index 6b68bad4..530c0c0d 100644
--- a/components/RangeSelector/samples/RangeSelector.md
+++ b/components/RangeSelector/samples/RangeSelector.md
@@ -16,6 +16,12 @@ A `RangeSelector` is pretty similar to a regular `Slider`, and shares some of it
> [!Sample RangeSelectorSample]
+## Vertical Orientation
+
+The `RangeSelector` also supports vertical orientation. Set the `Orientation` property to `Vertical` to display the range selector vertically.
+
+> [!Sample RangeSelectorVerticalSample]
+
> [!NOTE]
> If you are using a RangeSelector within a ScrollViewer you'll need to add some codes. This is because by default, the ScrollViewer will block the thumbs of the RangeSelector to capture the pointer.
diff --git a/components/RangeSelector/samples/RangeSelectorVerticalSample.xaml b/components/RangeSelector/samples/RangeSelectorVerticalSample.xaml
new file mode 100644
index 00000000..410e2524
--- /dev/null
+++ b/components/RangeSelector/samples/RangeSelectorVerticalSample.xaml
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
diff --git a/components/RangeSelector/samples/RangeSelectorVerticalSample.xaml.cs b/components/RangeSelector/samples/RangeSelectorVerticalSample.xaml.cs
new file mode 100644
index 00000000..69fc7b7d
--- /dev/null
+++ b/components/RangeSelector/samples/RangeSelectorVerticalSample.xaml.cs
@@ -0,0 +1,21 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using CommunityToolkit.WinUI.Controls;
+
+namespace RangeSelectorExperiment.Samples;
+
+[ToolkitSampleNumericOption("Minimum", 0, 0, 100, 1, false, Title = "Minimum")]
+[ToolkitSampleNumericOption("Maximum", 100, 0, 100, 1, false, Title = "Maximum")]
+[ToolkitSampleNumericOption("StepFrequency", 1, 0, 10, 1, false, Title = "StepFrequency")]
+[ToolkitSampleBoolOption("Enable", true, Title = "IsEnabled")]
+
+[ToolkitSample(id: nameof(RangeSelectorVerticalSample), "Vertical RangeSelector", description: $"A sample for showing how to create and use a vertical {nameof(RangeSelector)} control.")]
+public sealed partial class RangeSelectorVerticalSample : Page
+{
+ public RangeSelectorVerticalSample()
+ {
+ this.InitializeComponent();
+ }
+}
diff --git a/components/RangeSelector/src/RangeSelector.Input.Drag.cs b/components/RangeSelector/src/RangeSelector.Input.Drag.cs
index e8a8fd6a..ab84e06b 100644
--- a/components/RangeSelector/src/RangeSelector.Input.Drag.cs
+++ b/components/RangeSelector/src/RangeSelector.Input.Drag.cs
@@ -11,9 +11,12 @@ public partial class RangeSelector : Control
{
private void MinThumb_DragDelta(object sender, DragDeltaEventArgs e)
{
- _absolutePosition += e.HorizontalChange;
+ var isHorizontal = Orientation == Orientation.Horizontal;
+ _absolutePosition += isHorizontal ? e.HorizontalChange : e.VerticalChange;
- RangeStart = DragThumb(_minThumb, 0, DragWidth(), _absolutePosition);
+ RangeStart = isHorizontal
+ ? DragThumb(_minThumb, 0, Canvas.GetLeft(_maxThumb), _absolutePosition)
+ : DragThumbVertical(_minThumb, Canvas.GetTop(_maxThumb), DragWidth(), _absolutePosition);
if (_toolTipText != null)
{
@@ -23,9 +26,12 @@ private void MinThumb_DragDelta(object sender, DragDeltaEventArgs e)
private void MaxThumb_DragDelta(object sender, DragDeltaEventArgs e)
{
- _absolutePosition += e.HorizontalChange;
+ var isHorizontal = Orientation == Orientation.Horizontal;
+ _absolutePosition += isHorizontal ? e.HorizontalChange : e.VerticalChange;
- RangeEnd = DragThumb(_maxThumb, 0, DragWidth(), _absolutePosition);
+ RangeEnd = isHorizontal
+ ? DragThumb(_maxThumb, Canvas.GetLeft(_minThumb), DragWidth(), _absolutePosition)
+ : DragThumbVertical(_maxThumb, 0, Canvas.GetTop(_minThumb), _absolutePosition);
if (_toolTipText != null)
{
@@ -67,7 +73,9 @@ private void Thumb_DragCompleted(object sender, DragCompletedEventArgs e)
private double DragWidth()
{
- return _containerCanvas!.ActualWidth - _maxThumb!.Width;
+ return Orientation == Orientation.Horizontal
+ ? _containerCanvas!.ActualWidth - _maxThumb!.Width
+ : _containerCanvas!.ActualHeight - _maxThumb!.Height;
}
private double DragThumb(Thumb? thumb, double min, double max, double nextPos)
@@ -89,26 +97,68 @@ private double DragThumb(Thumb? thumb, double min, double max, double nextPos)
return Minimum + ((nextPos / DragWidth()) * (Maximum - Minimum));
}
+ private double DragThumbVertical(Thumb? thumb, double min, double max, double nextPos)
+ {
+ nextPos = Math.Max(min, nextPos);
+ nextPos = Math.Min(max, nextPos);
+
+ Canvas.SetTop(thumb, nextPos);
+
+ if (_toolTip != null && thumb != null)
+ {
+ var thumbCenter = nextPos + (thumb.Height / 2);
+ _toolTip.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
+ var ttHeight = _toolTip.DesiredSize.Height / 2;
+
+ Canvas.SetTop(_toolTip, thumbCenter - ttHeight);
+ UpdateToolTipPositionForVertical();
+ }
+
+ // Invert: top position (0) = Maximum, bottom position (DragWidth) = Minimum
+ return Maximum - ((nextPos / DragWidth()) * (Maximum - Minimum));
+ }
+
private void Thumb_DragStarted(Thumb thumb)
{
var useMin = thumb == _minThumb;
var otherThumb = useMin ? _maxThumb : _minThumb;
+ var isHorizontal = Orientation == Orientation.Horizontal;
- _absolutePosition = Canvas.GetLeft(thumb);
+ _absolutePosition = isHorizontal ? Canvas.GetLeft(thumb) : Canvas.GetTop(thumb);
Canvas.SetZIndex(thumb, 10);
Canvas.SetZIndex(otherThumb, 0);
_oldValue = RangeStart;
if (_toolTip != null)
{
- _toolTip.Visibility = Visibility.Visible;
- var thumbCenter = _absolutePosition + (thumb.Width / 2);
- _toolTip.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
- var ttWidth = _toolTip.ActualWidth / 2;
- Canvas.SetLeft(_toolTip, thumbCenter - ttWidth);
-
- if (_toolTipText != null)
- UpdateToolTipText(this, _toolTipText, useMin ? RangeStart : RangeEnd);
+ if (!isHorizontal && VerticalToolTipPlacement == VerticalToolTipPlacement.None)
+ {
+ _toolTip.Visibility = Visibility.Collapsed;
+ }
+ else
+ {
+ _toolTip.Visibility = Visibility.Visible;
+
+ // Update tooltip text first so Measure gets accurate size
+ if (_toolTipText != null)
+ {
+ UpdateToolTipText(this, _toolTipText, useMin ? RangeStart : RangeEnd);
+ }
+
+ _toolTip.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
+
+ if (isHorizontal)
+ {
+ var thumbCenter = _absolutePosition + (thumb.Width / 2);
+ Canvas.SetLeft(_toolTip, thumbCenter - (_toolTip.DesiredSize.Width / 2));
+ }
+ else
+ {
+ var thumbCenter = _absolutePosition + (thumb.Height / 2);
+ Canvas.SetTop(_toolTip, thumbCenter - (_toolTip.DesiredSize.Height / 2));
+ UpdateToolTipPositionForVertical();
+ }
+ }
}
VisualStateManager.GoToState(this, useMin ? MinPressedState : MaxPressedState, true);
diff --git a/components/RangeSelector/src/RangeSelector.Input.Key.cs b/components/RangeSelector/src/RangeSelector.Input.Key.cs
index 24151c14..eeb4c888 100644
--- a/components/RangeSelector/src/RangeSelector.Input.Key.cs
+++ b/components/RangeSelector/src/RangeSelector.Input.Key.cs
@@ -20,56 +20,66 @@ public partial class RangeSelector : Control
private void MinThumb_KeyDown(object sender, KeyRoutedEventArgs e)
{
+ var isHorizontal = Orientation == Orientation.Horizontal;
+ var handled = false;
+
switch (e.Key)
{
- case VirtualKey.Left:
+ case VirtualKey.Left when isHorizontal:
+ case VirtualKey.Down when !isHorizontal:
RangeStart -= StepFrequency;
- SyncThumbs(fromMinKeyDown: true);
- if (_toolTip != null)
- {
- _toolTip.Visibility = Visibility.Visible;
- }
-
- e.Handled = true;
+ handled = true;
break;
- case VirtualKey.Right:
+ case VirtualKey.Right when isHorizontal:
+ case VirtualKey.Up when !isHorizontal:
RangeStart += StepFrequency;
- SyncThumbs(fromMinKeyDown: true);
- if (_toolTip != null)
- {
- _toolTip.Visibility = Visibility.Visible;
- }
-
- e.Handled = true;
+ handled = true;
break;
}
+
+ if (handled)
+ {
+ SyncThumbs(fromMinKeyDown: true);
+ ShowToolTip();
+ e.Handled = true;
+ }
}
private void MaxThumb_KeyDown(object sender, KeyRoutedEventArgs e)
{
+ var isHorizontal = Orientation == Orientation.Horizontal;
+ var handled = false;
+
switch (e.Key)
{
- case VirtualKey.Left:
+ case VirtualKey.Left when isHorizontal:
+ case VirtualKey.Down when !isHorizontal:
RangeEnd -= StepFrequency;
- SyncThumbs(fromMaxKeyDown: true);
- if (_toolTip != null)
- {
- _toolTip.Visibility = Visibility.Visible;
- }
-
- e.Handled = true;
+ handled = true;
break;
- case VirtualKey.Right:
+ case VirtualKey.Right when isHorizontal:
+ case VirtualKey.Up when !isHorizontal:
RangeEnd += StepFrequency;
- SyncThumbs(fromMaxKeyDown: true);
- if (_toolTip != null)
- {
- _toolTip.Visibility = Visibility.Visible;
- }
-
- e.Handled = true;
+ handled = true;
break;
}
+
+ if (handled)
+ {
+ SyncThumbs(fromMaxKeyDown: true);
+ ShowToolTip();
+ e.Handled = true;
+ }
+ }
+
+ private void ShowToolTip()
+ {
+ var isHorizontal = Orientation == Orientation.Horizontal;
+ if (!isHorizontal && VerticalToolTipPlacement == VerticalToolTipPlacement.None) return;
+ if (_toolTip != null)
+ {
+ _toolTip.Visibility = Visibility.Visible;
+ }
}
private void Thumb_KeyUp(object sender, KeyRoutedEventArgs e)
@@ -78,6 +88,8 @@ private void Thumb_KeyUp(object sender, KeyRoutedEventArgs e)
{
case VirtualKey.Left:
case VirtualKey.Right:
+ case VirtualKey.Up:
+ case VirtualKey.Down:
if (_toolTip != null)
{
keyDebounceTimer.Debounce(
diff --git a/components/RangeSelector/src/RangeSelector.Input.Pointer.cs b/components/RangeSelector/src/RangeSelector.Input.Pointer.cs
index d27fd1be..fbd2023f 100644
--- a/components/RangeSelector/src/RangeSelector.Input.Pointer.cs
+++ b/components/RangeSelector/src/RangeSelector.Input.Pointer.cs
@@ -16,8 +16,12 @@ private void ContainerCanvas_PointerEntered(object sender, PointerRoutedEventArg
private void ContainerCanvas_PointerExited(object sender, PointerRoutedEventArgs e)
{
- var position = e.GetCurrentPoint(_containerCanvas).Position.X;
- var normalizedPosition = ((position / DragWidth()) * (Maximum - Minimum)) + Minimum;
+ var isHorizontal = Orientation == Orientation.Horizontal;
+ var point = e.GetCurrentPoint(_containerCanvas).Position;
+ var position = isHorizontal ? point.X : point.Y;
+ var normalizedPosition = isHorizontal
+ ? ((position / DragWidth()) * (Maximum - Minimum)) + Minimum
+ : Maximum - ((position / DragWidth()) * (Maximum - Minimum));
if (_pointerManipulatingMin)
{
@@ -40,13 +44,17 @@ private void ContainerCanvas_PointerExited(object sender, PointerRoutedEventArgs
_toolTip.Visibility = Visibility.Collapsed;
}
- VisualStateManager.GoToState(this, "Normal", false);
+ VisualStateManager.GoToState(this, NormalState, false);
}
private void ContainerCanvas_PointerReleased(object sender, PointerRoutedEventArgs e)
{
- var position = e.GetCurrentPoint(_containerCanvas).Position.X;
- var normalizedPosition = ((position / DragWidth()) * (Maximum - Minimum)) + Minimum;
+ var isHorizontal = Orientation == Orientation.Horizontal;
+ var point = e.GetCurrentPoint(_containerCanvas).Position;
+ var position = isHorizontal ? point.X : point.Y;
+ var normalizedPosition = isHorizontal
+ ? ((position / DragWidth()) * (Maximum - Minimum)) + Minimum
+ : Maximum - ((position / DragWidth()) * (Maximum - Minimum));
if (_pointerManipulatingMin)
{
@@ -74,12 +82,16 @@ private void ContainerCanvas_PointerReleased(object sender, PointerRoutedEventAr
private void ContainerCanvas_PointerMoved(object sender, PointerRoutedEventArgs e)
{
- var position = e.GetCurrentPoint(_containerCanvas).Position.X;
- var normalizedPosition = ((position / DragWidth()) * (Maximum - Minimum)) + Minimum;
+ var isHorizontal = Orientation == Orientation.Horizontal;
+ var point = e.GetCurrentPoint(_containerCanvas).Position;
+ var position = isHorizontal ? point.X : point.Y;
if (_pointerManipulatingMin)
{
- RangeStart = DragThumb(_minThumb, 0, DragWidth(), position);
+ RangeStart = isHorizontal
+ ? DragThumb(_minThumb, 0, Canvas.GetLeft(_maxThumb), position)
+ : DragThumbVertical(_minThumb, Canvas.GetTop(_maxThumb), DragWidth(), position);
+
if (_toolTipText is not null)
{
UpdateToolTipText(this, _toolTipText, RangeStart);
@@ -87,9 +99,12 @@ private void ContainerCanvas_PointerMoved(object sender, PointerRoutedEventArgs
}
else if (_pointerManipulatingMax)
{
+ RangeEnd = isHorizontal
+ ? DragThumb(_maxThumb, Canvas.GetLeft(_minThumb), DragWidth(), position)
+ : DragThumbVertical(_maxThumb, 0, Canvas.GetTop(_minThumb), position);
+
if (_toolTipText is not null)
{
- RangeEnd = DragThumb(_maxThumb, 0, DragWidth(), position);
UpdateToolTipText(this, _toolTipText, RangeEnd);
}
}
@@ -97,8 +112,13 @@ private void ContainerCanvas_PointerMoved(object sender, PointerRoutedEventArgs
private void ContainerCanvas_PointerPressed(object sender, PointerRoutedEventArgs e)
{
- var position = e.GetCurrentPoint(_containerCanvas).Position.X;
- var normalizedPosition = position * Math.Abs(Maximum - Minimum) / DragWidth();
+ var isHorizontal = Orientation == Orientation.Horizontal;
+ var point = e.GetCurrentPoint(_containerCanvas).Position;
+ var position = isHorizontal ? point.X : point.Y;
+ var normalizedPosition = isHorizontal
+ ? position * Math.Abs(Maximum - Minimum) / DragWidth()
+ : Maximum - ((position / DragWidth()) * (Maximum - Minimum));
+
double upperValueDiff = Math.Abs(RangeEnd - normalizedPosition);
double lowerValueDiff = Math.Abs(RangeStart - normalizedPosition);
diff --git a/components/RangeSelector/src/RangeSelector.Properties.cs b/components/RangeSelector/src/RangeSelector.Properties.cs
index 6377df37..9d75e075 100644
--- a/components/RangeSelector/src/RangeSelector.Properties.cs
+++ b/components/RangeSelector/src/RangeSelector.Properties.cs
@@ -9,6 +9,16 @@ namespace CommunityToolkit.WinUI.Controls;
///
public partial class RangeSelector : Control
{
+ ///
+ /// Identifies the property.
+ ///
+ public static readonly DependencyProperty OrientationProperty =
+ DependencyProperty.Register(
+ nameof(Orientation),
+ typeof(Orientation),
+ typeof(RangeSelector),
+ new PropertyMetadata(Orientation.Horizontal, OrientationChangedCallback));
+
///
/// Identifies the property.
///
@@ -59,6 +69,16 @@ public partial class RangeSelector : Control
typeof(RangeSelector),
new PropertyMetadata(DefaultStepFrequency));
+ ///
+ /// Identifies the property.
+ ///
+ public static readonly DependencyProperty VerticalToolTipPlacementProperty =
+ DependencyProperty.Register(
+ nameof(VerticalToolTipPlacement),
+ typeof(VerticalToolTipPlacement),
+ typeof(RangeSelector),
+ new PropertyMetadata(VerticalToolTipPlacement.Right));
+
///
/// Gets or sets the absolute minimum value of the range.
///
@@ -119,6 +139,45 @@ public double StepFrequency
set => SetValue(StepFrequencyProperty, value);
}
+ ///
+ /// Gets or sets the orientation of the range selector (horizontal or vertical).
+ ///
+ ///
+ /// The orientation of the range selector. Default is .
+ ///
+ public Orientation Orientation
+ {
+ get => (Orientation)GetValue(OrientationProperty);
+ set => SetValue(OrientationProperty, value);
+ }
+
+ ///
+ /// Gets or sets the placement of the tooltip for the vertical range selector.
+ /// This property only takes effect when is set to .
+ ///
+ ///
+ /// The placement of the tooltip. Default is .
+ ///
+ public VerticalToolTipPlacement VerticalToolTipPlacement
+ {
+ get => (VerticalToolTipPlacement)GetValue(VerticalToolTipPlacementProperty);
+ set => SetValue(VerticalToolTipPlacementProperty, value);
+ }
+
+ private static void OrientationChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
+ {
+ var rangeSelector = d as RangeSelector;
+
+ if (rangeSelector == null || !rangeSelector._valuesAssigned)
+ {
+ return;
+ }
+
+ VisualStateManager.GoToState(rangeSelector, rangeSelector.Orientation == Orientation.Horizontal ? HorizontalState : VerticalState, true);
+
+ rangeSelector.SyncThumbs();
+ }
+
private static void MinimumChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var rangeSelector = d as RangeSelector;
diff --git a/components/RangeSelector/src/RangeSelector.ToolTip.Placement.cs b/components/RangeSelector/src/RangeSelector.ToolTip.Placement.cs
new file mode 100644
index 00000000..3ff8ee28
--- /dev/null
+++ b/components/RangeSelector/src/RangeSelector.ToolTip.Placement.cs
@@ -0,0 +1,27 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace CommunityToolkit.WinUI.Controls;
+
+///
+/// Enumeration used to determine the placement of the tooltip
+/// for the vertical RangeSelector.
+///
+public enum VerticalToolTipPlacement
+{
+ ///
+ /// Tooltip is placed to the right of the thumb.
+ ///
+ Right,
+
+ ///
+ /// Tooltip is placed to the left of the thumb.
+ ///
+ Left,
+
+ ///
+ /// Tooltip is not displayed.
+ ///
+ None
+}
diff --git a/components/RangeSelector/src/RangeSelector.cs b/components/RangeSelector/src/RangeSelector.cs
index 7cf3bdbb..55805d6d 100644
--- a/components/RangeSelector/src/RangeSelector.cs
+++ b/components/RangeSelector/src/RangeSelector.cs
@@ -16,6 +16,8 @@ namespace CommunityToolkit.WinUI.Controls;
[TemplateVisualState(Name = MinPressedState, GroupName = CommonStates)]
[TemplateVisualState(Name = MaxPressedState, GroupName = CommonStates)]
[TemplateVisualState(Name = DisabledState, GroupName = CommonStates)]
+[TemplateVisualState(Name = HorizontalState, GroupName = OrientationStates)]
+[TemplateVisualState(Name = VerticalState, GroupName = OrientationStates)]
[TemplatePart(Name = "OutOfRangeContentContainer", Type = typeof(Border))]
[TemplatePart(Name = "ActiveRectangle", Type = typeof(Rectangle))]
[TemplatePart(Name = "MinThumb", Type = typeof(Thumb))]
@@ -33,6 +35,9 @@ public partial class RangeSelector : Control
internal const string DisabledState = "Disabled";
internal const string MinPressedState = "MinPressed";
internal const string MaxPressedState = "MaxPressed";
+ internal const string OrientationStates = "OrientationStates";
+ internal const string HorizontalState = "Horizontal";
+ internal const string VerticalState = "Vertical";
private const double Epsilon = 0.01;
private const double DefaultMinimum = 0.0;
@@ -135,6 +140,7 @@ protected override void OnApplyTemplate()
}
VisualStateManager.GoToState(this, IsEnabled ? NormalState : DisabledState, false);
+ VisualStateManager.GoToState(this, Orientation == Orientation.Horizontal ? HorizontalState : VerticalState, false);
IsEnabledChanged += RangeSelector_IsEnabledChanged;
@@ -142,9 +148,19 @@ protected override void OnApplyTemplate()
var tb = new TextBlock { Text = Maximum.ToString() };
tb.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
+ // Ensure thumbs and active rectangle are synced after the control is fully loaded
+ Loaded -= RangeSelector_Loaded;
+ Loaded += RangeSelector_Loaded;
+
base.OnApplyTemplate();
}
+ private void RangeSelector_Loaded(object sender, RoutedEventArgs e)
+ {
+ Loaded -= RangeSelector_Loaded;
+ SyncThumbs();
+ }
+
private static void UpdateToolTipText(RangeSelector rangeSelector, TextBlock toolTip, double newValue)
{
if (toolTip != null)
@@ -237,24 +253,46 @@ private double MoveToStepFrequency(double rangeValue)
private void SyncThumbs(bool fromMinKeyDown = false, bool fromMaxKeyDown = false)
{
- if (_containerCanvas == null)
+ if (_containerCanvas == null || _minThumb == null || _maxThumb == null)
{
return;
}
- var relativeLeft = ((RangeStart - Minimum) / (Maximum - Minimum)) * DragWidth();
- var relativeRight = ((RangeEnd - Minimum) / (Maximum - Minimum)) * DragWidth();
+ var relativeStart = ((RangeStart - Minimum) / (Maximum - Minimum)) * DragWidth();
+ var relativeEnd = ((RangeEnd - Minimum) / (Maximum - Minimum)) * DragWidth();
+ var isHorizontal = Orientation == Orientation.Horizontal;
- Canvas.SetLeft(_minThumb, relativeLeft);
- Canvas.SetLeft(_maxThumb, relativeRight);
+ if (isHorizontal)
+ {
+ Canvas.SetLeft(_minThumb, relativeStart);
+ Canvas.SetLeft(_maxThumb, relativeEnd);
+ }
+ else
+ {
+ // Vertical: invert positions so min is at bottom, max is at top
+ Canvas.SetTop(_minThumb, DragWidth() - relativeStart);
+ Canvas.SetTop(_maxThumb, DragWidth() - relativeEnd);
+ }
if (fromMinKeyDown || fromMaxKeyDown)
{
- DragThumb(
- fromMinKeyDown ? _minThumb : _maxThumb,
- fromMinKeyDown ? 0 : Canvas.GetLeft(_minThumb),
- fromMinKeyDown ? Canvas.GetLeft(_maxThumb) : DragWidth(),
- fromMinKeyDown ? relativeLeft : relativeRight);
+ var thumb = fromMinKeyDown ? _minThumb : _maxThumb;
+ var position = fromMinKeyDown ? relativeStart : relativeEnd;
+
+ if (isHorizontal)
+ {
+ var min = fromMinKeyDown ? 0 : Canvas.GetLeft(_minThumb);
+ var max = fromMinKeyDown ? Canvas.GetLeft(_maxThumb) : DragWidth();
+ DragThumb(thumb, min, max, position);
+ }
+ else
+ {
+ var invertedPosition = DragWidth() - position;
+ var min = fromMinKeyDown ? Canvas.GetTop(_maxThumb) : 0;
+ var max = fromMinKeyDown ? DragWidth() : Canvas.GetTop(_minThumb);
+ DragThumbVertical(thumb, min, max, invertedPosition);
+ }
+
if (_toolTipText != null)
{
UpdateToolTipText(this, _toolTipText, fromMinKeyDown ? RangeStart : RangeEnd);
@@ -266,29 +304,55 @@ private void SyncThumbs(bool fromMinKeyDown = false, bool fromMaxKeyDown = false
private void SyncActiveRectangle()
{
- if (_containerCanvas == null)
+ if (_containerCanvas == null || _minThumb == null || _maxThumb == null || _activeRectangle == null)
{
return;
}
- if (_minThumb == null)
+ if (Orientation == Orientation.Horizontal)
{
- return;
+ var relativeLeft = Canvas.GetLeft(_minThumb);
+ Canvas.SetLeft(_activeRectangle, relativeLeft);
+ Canvas.SetTop(_activeRectangle, (_containerCanvas.ActualHeight - _activeRectangle.ActualHeight) / 2);
+ _activeRectangle.Width = Math.Max(0, Canvas.GetLeft(_maxThumb) - relativeLeft);
}
-
- if (_maxThumb == null)
+ else
{
- return;
+ var relativeTop = Canvas.GetTop(_maxThumb);
+ Canvas.SetTop(_activeRectangle, relativeTop);
+ Canvas.SetLeft(_activeRectangle, (_containerCanvas.ActualWidth - _activeRectangle.ActualWidth) / 2);
+ _activeRectangle.Height = Math.Max(0, Canvas.GetTop(_minThumb) - relativeTop);
}
-
- var relativeLeft = Canvas.GetLeft(_minThumb);
- Canvas.SetLeft(_activeRectangle, relativeLeft);
- Canvas.SetTop(_activeRectangle, (_containerCanvas.ActualHeight - _activeRectangle!.ActualHeight) / 2);
- _activeRectangle.Width = Math.Max(0, Canvas.GetLeft(_maxThumb) - Canvas.GetLeft(_minThumb));
}
private void RangeSelector_IsEnabledChanged(object sender, DependencyPropertyChangedEventArgs e)
{
VisualStateManager.GoToState(this, IsEnabled ? NormalState : DisabledState, true);
}
+
+ private void UpdateToolTipPositionForVertical()
+ {
+ if (_toolTip == null || _containerCanvas == null)
+ {
+ return;
+ }
+
+ // Offset to position tooltip beside the thumb
+ const double toolTipOffset = 52;
+
+ switch (VerticalToolTipPlacement)
+ {
+ case VerticalToolTipPlacement.Right:
+ Canvas.SetLeft(_toolTip, toolTipOffset);
+ break;
+ case VerticalToolTipPlacement.Left:
+ _toolTip.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
+ var toolTipWidth = _toolTip.DesiredSize.Width;
+ Canvas.SetLeft(_toolTip, -toolTipWidth - (toolTipOffset - _containerCanvas.ActualWidth));
+ break;
+ case VerticalToolTipPlacement.None:
+ _toolTip.Visibility = Visibility.Collapsed;
+ break;
+ }
+ }
}
diff --git a/components/RangeSelector/src/RangeSelector.xaml b/components/RangeSelector/src/RangeSelector.xaml
index 934c62a3..456afb0f 100644
--- a/components/RangeSelector/src/RangeSelector.xaml
+++ b/components/RangeSelector/src/RangeSelector.xaml
@@ -17,7 +17,8 @@
-
+
+
@@ -246,6 +247,25 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+