diff --git a/src/Core_30/HandyControlDemo_Core_30/HandyControlDemo_Core30.csproj b/src/Core_30/HandyControlDemo_Core_30/HandyControlDemo_Core30.csproj
index 0fc398af..796f9876 100644
--- a/src/Core_30/HandyControlDemo_Core_30/HandyControlDemo_Core30.csproj
+++ b/src/Core_30/HandyControlDemo_Core_30/HandyControlDemo_Core30.csproj
@@ -349,6 +349,9 @@
Resources\Img\LeftMainContent\MainMenuControl_16x.png
+
+ Resources\Img\LeftMainContent\brackets_Square_16xLG.png
+
diff --git a/src/HandyControl.sln b/src/HandyControl.sln
index be1e539b..e6c455be 100644
--- a/src/HandyControl.sln
+++ b/src/HandyControl.sln
@@ -95,13 +95,9 @@ Global
{BE4A567D-B6E0-413E-8F64-E1A53B4F9366}.Debug-Core30|Any CPU.Build.0 = Debug|Any CPU
{BE4A567D-B6E0-413E-8F64-E1A53B4F9366}.Debug-Net40|Any CPU.ActiveCfg = Debug|Any CPU
{BE4A567D-B6E0-413E-8F64-E1A53B4F9366}.Debug-Net45|Any CPU.ActiveCfg = Debug|Any CPU
- {BE4A567D-B6E0-413E-8F64-E1A53B4F9366}.Debug-Net45|Any CPU.Build.0 = Debug|Any CPU
{BE4A567D-B6E0-413E-8F64-E1A53B4F9366}.Debug-Net462|Any CPU.ActiveCfg = Debug|Any CPU
- {BE4A567D-B6E0-413E-8F64-E1A53B4F9366}.Debug-Net462|Any CPU.Build.0 = Debug|Any CPU
{BE4A567D-B6E0-413E-8F64-E1A53B4F9366}.Debug-Net47|Any CPU.ActiveCfg = Debug|Any CPU
- {BE4A567D-B6E0-413E-8F64-E1A53B4F9366}.Debug-Net47|Any CPU.Build.0 = Debug|Any CPU
{BE4A567D-B6E0-413E-8F64-E1A53B4F9366}.Debug-Net48|Any CPU.ActiveCfg = Debug|Any CPU
- {BE4A567D-B6E0-413E-8F64-E1A53B4F9366}.Debug-Net48|Any CPU.Build.0 = Debug|Any CPU
{BE4A567D-B6E0-413E-8F64-E1A53B4F9366}.Release-Core30|Any CPU.ActiveCfg = Release|Any CPU
{BE4A567D-B6E0-413E-8F64-E1A53B4F9366}.Release-Core30|Any CPU.Build.0 = Release|Any CPU
{BE4A567D-B6E0-413E-8F64-E1A53B4F9366}.Release-Net40|Any CPU.ActiveCfg = Release|Any CPU
@@ -117,13 +113,9 @@ Global
{D7107690-8592-4F9F-9379-9B82C1C15D2A}.Debug-Core30|Any CPU.Build.0 = Debug|Any CPU
{D7107690-8592-4F9F-9379-9B82C1C15D2A}.Debug-Net40|Any CPU.ActiveCfg = Debug|Any CPU
{D7107690-8592-4F9F-9379-9B82C1C15D2A}.Debug-Net45|Any CPU.ActiveCfg = Debug|Any CPU
- {D7107690-8592-4F9F-9379-9B82C1C15D2A}.Debug-Net45|Any CPU.Build.0 = Debug|Any CPU
{D7107690-8592-4F9F-9379-9B82C1C15D2A}.Debug-Net462|Any CPU.ActiveCfg = Debug|Any CPU
- {D7107690-8592-4F9F-9379-9B82C1C15D2A}.Debug-Net462|Any CPU.Build.0 = Debug|Any CPU
{D7107690-8592-4F9F-9379-9B82C1C15D2A}.Debug-Net47|Any CPU.ActiveCfg = Debug|Any CPU
- {D7107690-8592-4F9F-9379-9B82C1C15D2A}.Debug-Net47|Any CPU.Build.0 = Debug|Any CPU
{D7107690-8592-4F9F-9379-9B82C1C15D2A}.Debug-Net48|Any CPU.ActiveCfg = Debug|Any CPU
- {D7107690-8592-4F9F-9379-9B82C1C15D2A}.Debug-Net48|Any CPU.Build.0 = Debug|Any CPU
{D7107690-8592-4F9F-9379-9B82C1C15D2A}.Release-Core30|Any CPU.ActiveCfg = Release|Any CPU
{D7107690-8592-4F9F-9379-9B82C1C15D2A}.Release-Core30|Any CPU.Build.0 = Release|Any CPU
{D7107690-8592-4F9F-9379-9B82C1C15D2A}.Release-Net40|Any CPU.ActiveCfg = Release|Any CPU
@@ -139,13 +131,9 @@ Global
{32204503-2EF0-4681-AE13-AA1FEB6C658A}.Debug-Net40|Any CPU.ActiveCfg = Debug|Any CPU
{32204503-2EF0-4681-AE13-AA1FEB6C658A}.Debug-Net40|Any CPU.Build.0 = Debug|Any CPU
{32204503-2EF0-4681-AE13-AA1FEB6C658A}.Debug-Net45|Any CPU.ActiveCfg = Debug|Any CPU
- {32204503-2EF0-4681-AE13-AA1FEB6C658A}.Debug-Net45|Any CPU.Build.0 = Debug|Any CPU
{32204503-2EF0-4681-AE13-AA1FEB6C658A}.Debug-Net462|Any CPU.ActiveCfg = Debug|Any CPU
- {32204503-2EF0-4681-AE13-AA1FEB6C658A}.Debug-Net462|Any CPU.Build.0 = Debug|Any CPU
{32204503-2EF0-4681-AE13-AA1FEB6C658A}.Debug-Net47|Any CPU.ActiveCfg = Debug|Any CPU
- {32204503-2EF0-4681-AE13-AA1FEB6C658A}.Debug-Net47|Any CPU.Build.0 = Debug|Any CPU
{32204503-2EF0-4681-AE13-AA1FEB6C658A}.Debug-Net48|Any CPU.ActiveCfg = Debug|Any CPU
- {32204503-2EF0-4681-AE13-AA1FEB6C658A}.Debug-Net48|Any CPU.Build.0 = Debug|Any CPU
{32204503-2EF0-4681-AE13-AA1FEB6C658A}.Release-Core30|Any CPU.ActiveCfg = Release|Any CPU
{32204503-2EF0-4681-AE13-AA1FEB6C658A}.Release-Net40|Any CPU.ActiveCfg = Release|Any CPU
{32204503-2EF0-4681-AE13-AA1FEB6C658A}.Release-Net40|Any CPU.Build.0 = Release|Any CPU
@@ -161,13 +149,9 @@ Global
{D8AE88F8-C36B-4D10-A7F9-22FFCFBA5231}.Debug-Net40|Any CPU.ActiveCfg = Debug|Any CPU
{D8AE88F8-C36B-4D10-A7F9-22FFCFBA5231}.Debug-Net40|Any CPU.Build.0 = Debug|Any CPU
{D8AE88F8-C36B-4D10-A7F9-22FFCFBA5231}.Debug-Net45|Any CPU.ActiveCfg = Debug|Any CPU
- {D8AE88F8-C36B-4D10-A7F9-22FFCFBA5231}.Debug-Net45|Any CPU.Build.0 = Debug|Any CPU
{D8AE88F8-C36B-4D10-A7F9-22FFCFBA5231}.Debug-Net462|Any CPU.ActiveCfg = Debug|Any CPU
- {D8AE88F8-C36B-4D10-A7F9-22FFCFBA5231}.Debug-Net462|Any CPU.Build.0 = Debug|Any CPU
{D8AE88F8-C36B-4D10-A7F9-22FFCFBA5231}.Debug-Net47|Any CPU.ActiveCfg = Debug|Any CPU
- {D8AE88F8-C36B-4D10-A7F9-22FFCFBA5231}.Debug-Net47|Any CPU.Build.0 = Debug|Any CPU
{D8AE88F8-C36B-4D10-A7F9-22FFCFBA5231}.Debug-Net48|Any CPU.ActiveCfg = Debug|Any CPU
- {D8AE88F8-C36B-4D10-A7F9-22FFCFBA5231}.Debug-Net48|Any CPU.Build.0 = Debug|Any CPU
{D8AE88F8-C36B-4D10-A7F9-22FFCFBA5231}.Release-Core30|Any CPU.ActiveCfg = Release|Any CPU
{D8AE88F8-C36B-4D10-A7F9-22FFCFBA5231}.Release-Net40|Any CPU.ActiveCfg = Release|Any CPU
{D8AE88F8-C36B-4D10-A7F9-22FFCFBA5231}.Release-Net40|Any CPU.Build.0 = Release|Any CPU
diff --git a/src/Net_40/HandyControlDemo_Net_40/HandyControlDemo_Net_40.csproj b/src/Net_40/HandyControlDemo_Net_40/HandyControlDemo_Net_40.csproj
index f6f98c80..61536a9e 100644
--- a/src/Net_40/HandyControlDemo_Net_40/HandyControlDemo_Net_40.csproj
+++ b/src/Net_40/HandyControlDemo_Net_40/HandyControlDemo_Net_40.csproj
@@ -395,6 +395,9 @@
TextTemplatingFileGenerator
MessageToken.cs
+
+ Resources\Img\LeftMainContent\brackets_Square_16xLG.png
+
Resources\Img\LeftMainContent\GridPane_16x.png
diff --git a/src/Shared/HandyControlDemo_Shared/UserControl/Controls/RangeSliderDemoCtl.xaml b/src/Shared/HandyControlDemo_Shared/UserControl/Controls/RangeSliderDemoCtl.xaml
index 9a8c3727..0dd0f1b7 100644
--- a/src/Shared/HandyControlDemo_Shared/UserControl/Controls/RangeSliderDemoCtl.xaml
+++ b/src/Shared/HandyControlDemo_Shared/UserControl/Controls/RangeSliderDemoCtl.xaml
@@ -3,5 +3,20 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:hc="https://handyorg.github.io/handycontrol"
Background="{DynamicResource RegionBrush}">
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Shared/HandyControl_Shared/Controls/Cover/CoverView/CoverView.cs b/src/Shared/HandyControl_Shared/Controls/Cover/CoverView/CoverView.cs
index 0e80402c..96c8bf46 100644
--- a/src/Shared/HandyControl_Shared/Controls/Cover/CoverView/CoverView.cs
+++ b/src/Shared/HandyControl_Shared/Controls/Cover/CoverView/CoverView.cs
@@ -135,7 +135,7 @@ namespace HandyControl.Controls
public static readonly DependencyProperty ItemContentHeightProperty = DependencyProperty.Register(
"ItemContentHeight", typeof(double), typeof(CoverView), new PropertyMetadata(ValueBoxes.Double300Box),
- value => ValidateHelper.IsInRangeOfPosDouble(value, true));
+ ValidateHelper.IsInRangeOfPosDoubleIncludeZero);
public double ItemContentHeight
{
diff --git a/src/Shared/HandyControl_Shared/Controls/Cover/CoverView/CoverViewContent.cs b/src/Shared/HandyControl_Shared/Controls/Cover/CoverView/CoverViewContent.cs
index eb7f3e8c..9cb74208 100644
--- a/src/Shared/HandyControl_Shared/Controls/Cover/CoverView/CoverViewContent.cs
+++ b/src/Shared/HandyControl_Shared/Controls/Cover/CoverView/CoverViewContent.cs
@@ -43,7 +43,7 @@ namespace HandyControl.Controls
}
internal static readonly DependencyProperty ManualHeightProperty = DependencyProperty.Register(
- "ManualHeight", typeof(double), typeof(CoverViewContent), new PropertyMetadata(ValueBoxes.Double0Box), value => ValidateHelper.IsInRangeOfPosDouble(value, true));
+ "ManualHeight", typeof(double), typeof(CoverViewContent), new PropertyMetadata(ValueBoxes.Double0Box), ValidateHelper.IsInRangeOfPosDoubleIncludeZero);
internal double ManualHeight
{
@@ -53,7 +53,7 @@ namespace HandyControl.Controls
public static readonly DependencyProperty ContentHeightProperty = DependencyProperty.Register(
"ContentHeight", typeof(double), typeof(CoverViewContent), new PropertyMetadata(ValueBoxes.Double300Box),
- value => ValidateHelper.IsInRangeOfPosDouble(value, true));
+ ValidateHelper.IsInRangeOfPosDoubleIncludeZero);
public double ContentHeight
{
diff --git a/src/Shared/HandyControl_Shared/Controls/Grid/Row.cs b/src/Shared/HandyControl_Shared/Controls/Grid/Row.cs
index 155ed71b..e659178d 100644
--- a/src/Shared/HandyControl_Shared/Controls/Grid/Row.cs
+++ b/src/Shared/HandyControl_Shared/Controls/Grid/Row.cs
@@ -14,11 +14,9 @@ namespace HandyControl.Controls
private double _maxChildDesiredHeight;
public static readonly DependencyProperty GutterProperty = DependencyProperty.Register(
- "Gutter", typeof(double), typeof(Row), new PropertyMetadata(ValueBoxes.Double0Box, null, OnGutterCoerce), OnGutterValidate);
+ "Gutter", typeof(double), typeof(Row), new PropertyMetadata(ValueBoxes.Double0Box, null, OnGutterCoerce), ValidateHelper.IsInRangeOfPosDoubleIncludeZero);
- private static object OnGutterCoerce(DependencyObject d, object basevalue) => OnGutterValidate(basevalue) ? basevalue : .0;
-
- private static bool OnGutterValidate(object value) => ValidateHelper.IsInRangeOfPosDouble(value, true);
+ private static object OnGutterCoerce(DependencyObject d, object basevalue) => ValidateHelper.IsInRangeOfPosDoubleIncludeZero(basevalue) ? basevalue : .0;
public double Gutter
{
@@ -44,8 +42,6 @@ namespace HandyControl.Controls
}
}
- var itemWidth = constraint.Width / ColLayout.ColMaxCellCount;
- var childBounds = new Rect(-gutterHalf, -gutterHalf, 0, _maxChildDesiredHeight);
_layoutStatus = ColLayout.GetLayoutStatus(constraint.Width);
foreach (var child in InternalChildren.OfType())
@@ -55,15 +51,9 @@ namespace HandyControl.Controls
if (totalCellCount > ColLayout.ColMaxCellCount)
{
- childBounds.X = -gutterHalf;
- childBounds.Y += _maxChildDesiredHeight;
totalCellCount = cellCount;
totalRowCount++;
}
-
- var childWidth = cellCount * itemWidth;
- childBounds.Width = childWidth;
- childBounds.X += childWidth + child.Offset * itemWidth;
}
return new Size(0, _maxChildDesiredHeight * totalRowCount - Gutter);
diff --git a/src/Shared/HandyControl_Shared/Controls/Input/NumericUpDown.cs b/src/Shared/HandyControl_Shared/Controls/Input/NumericUpDown.cs
index fa59e270..df9f0c73 100644
--- a/src/Shared/HandyControl_Shared/Controls/Input/NumericUpDown.cs
+++ b/src/Shared/HandyControl_Shared/Controls/Input/NumericUpDown.cs
@@ -153,7 +153,7 @@ namespace HandyControl.Controls
public static readonly DependencyProperty ValueProperty = DependencyProperty.Register(
"Value", typeof(double), typeof(NumericUpDown),
new FrameworkPropertyMetadata(ValueBoxes.Double0Box, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
- OnValueChanged, CoerceValue), ArithmeticHelper.IsValidDoubleValue);
+ OnValueChanged, CoerceValue), ValidateHelper.IsInRangeOfDouble);
private static void OnValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
@@ -208,7 +208,7 @@ namespace HandyControl.Controls
/// 最大值
///
public static readonly DependencyProperty MaximumProperty = DependencyProperty.Register(
- "Maximum", typeof(double), typeof(NumericUpDown), new PropertyMetadata(double.MaxValue, OnMaximumChanged, CoerceMaximum), ArithmeticHelper.IsValidDoubleValue);
+ "Maximum", typeof(double), typeof(NumericUpDown), new PropertyMetadata(double.MaxValue, OnMaximumChanged, CoerceMaximum), ValidateHelper.IsInRangeOfDouble);
private static void OnMaximumChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
@@ -236,7 +236,7 @@ namespace HandyControl.Controls
/// 最小值
///
public static readonly DependencyProperty MinimumProperty = DependencyProperty.Register(
- "Minimum", typeof(double), typeof(NumericUpDown), new PropertyMetadata(ValueBoxes.Double0Box, OnMinimumChanged, CoerceMinimum), ArithmeticHelper.IsValidDoubleValue);
+ "Minimum", typeof(double), typeof(NumericUpDown), new PropertyMetadata(ValueBoxes.Double0Box, OnMinimumChanged, CoerceMinimum), ValidateHelper.IsInRangeOfDouble);
private static void OnMinimumChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
diff --git a/src/Shared/HandyControl_Shared/Controls/Slider/CompareSlider.cs b/src/Shared/HandyControl_Shared/Controls/Slider/CompareSlider/CompareSlider.cs
similarity index 100%
rename from src/Shared/HandyControl_Shared/Controls/Slider/CompareSlider.cs
rename to src/Shared/HandyControl_Shared/Controls/Slider/CompareSlider/CompareSlider.cs
diff --git a/src/Shared/HandyControl_Shared/Controls/Slider/CompareTrack.cs b/src/Shared/HandyControl_Shared/Controls/Slider/CompareSlider/CompareTrack.cs
similarity index 100%
rename from src/Shared/HandyControl_Shared/Controls/Slider/CompareTrack.cs
rename to src/Shared/HandyControl_Shared/Controls/Slider/CompareSlider/CompareTrack.cs
diff --git a/src/Shared/HandyControl_Shared/Controls/Slider/RangeSlider.cs b/src/Shared/HandyControl_Shared/Controls/Slider/RangeSlider.cs
deleted file mode 100644
index 9b0b2b80..00000000
--- a/src/Shared/HandyControl_Shared/Controls/Slider/RangeSlider.cs
+++ /dev/null
@@ -1,15 +0,0 @@
-using System.ComponentModel;
-using System.Windows;
-using System.Windows.Controls.Primitives;
-
-namespace HandyControl.Controls
-{
- [DefaultEvent("ValueChanged"), DefaultProperty("Value")]
- [TemplatePart(Name = "PART_Track", Type = typeof(Track))]
- [TemplatePart(Name = "PART_SelectionRange", Type = typeof(FrameworkElement))]
- public class RangeSlider : RangeBase
- {
-
-
- }
-}
\ No newline at end of file
diff --git a/src/Shared/HandyControl_Shared/Controls/Slider/RangeSlider/RangeSlider.cs b/src/Shared/HandyControl_Shared/Controls/Slider/RangeSlider/RangeSlider.cs
new file mode 100644
index 00000000..19289546
--- /dev/null
+++ b/src/Shared/HandyControl_Shared/Controls/Slider/RangeSlider/RangeSlider.cs
@@ -0,0 +1,655 @@
+// Adapted from https://referencesource.microsoft.com/#PresentationFramework/src/Framework/System/Windows/Controls/Slider.cs
+
+using System;
+using System.ComponentModel;
+using System.Globalization;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Controls.Primitives;
+using System.Windows.Input;
+using System.Windows.Media;
+using HandyControl.Data;
+using HandyControl.Expression.Drawing;
+using HandyControl.Tools;
+
+namespace HandyControl.Controls
+{
+ [DefaultEvent("ValueChanged"), DefaultProperty("Value")]
+ [TemplatePart(Name = ElementTrack, Type = typeof(Track))]
+ public class RangeSlider : TwoWayRangeBase
+ {
+ private const string ElementTrack= "PART_Track";
+
+ private RangeTrack _track;
+
+ private readonly ToolTip _autoToolTipStart = null;
+
+ private readonly ToolTip _autoToolTipEnd = null;
+
+ private RangeThumb _thumbCurrent;
+
+ private object _thumbOriginalToolTip;
+
+ private Point _originThumbPoint;
+
+ private Point _previousScreenCoordPosition;
+
+ static RangeSlider()
+ {
+ InitializeCommands();
+
+ MinimumProperty.OverrideMetadata(typeof(RangeSlider), new FrameworkPropertyMetadata(ValueBoxes.Double0Box, FrameworkPropertyMetadataOptions.AffectsMeasure));
+ MaximumProperty.OverrideMetadata(typeof(RangeSlider), new FrameworkPropertyMetadata(ValueBoxes.Double10Box, FrameworkPropertyMetadataOptions.AffectsMeasure));
+ ValueStartProperty.OverrideMetadata(typeof(RangeSlider), new FrameworkPropertyMetadata(ValueBoxes.Double0Box, FrameworkPropertyMetadataOptions.AffectsMeasure));
+ ValueEndProperty.OverrideMetadata(typeof(RangeSlider), new FrameworkPropertyMetadata(ValueBoxes.Double0Box, FrameworkPropertyMetadataOptions.AffectsMeasure));
+
+ // Register Event Handler for the Thumb
+ EventManager.RegisterClassHandler(typeof(RangeSlider), Thumb.DragStartedEvent, new DragStartedEventHandler(OnThumbDragStarted));
+ EventManager.RegisterClassHandler(typeof(RangeSlider), Thumb.DragDeltaEvent, new DragDeltaEventHandler(OnThumbDragDelta));
+ EventManager.RegisterClassHandler(typeof(RangeSlider), Thumb.DragCompletedEvent, new DragCompletedEventHandler(OnThumbDragCompleted));
+
+ // Listen to MouseLeftButtonDown event to determine if slide should move focus to itself
+ EventManager.RegisterClassHandler(typeof(RangeSlider), Mouse.MouseDownEvent, new MouseButtonEventHandler(OnMouseLeftButtonDown), true);
+ }
+
+ public RangeSlider()
+ {
+ CommandBindings.Add(new CommandBinding(IncreaseLarge, OnIncreaseLarge));
+ CommandBindings.Add(new CommandBinding(IncreaseSmall, OnIncreaseSmall));
+
+ CommandBindings.Add(new CommandBinding(DecreaseLarge, OnDecreaseLarge));
+ CommandBindings.Add(new CommandBinding(DecreaseSmall, OnDecreaseSmall));
+
+ CommandBindings.Add(new CommandBinding(CenterLarge, OnCenterLarge));
+ CommandBindings.Add(new CommandBinding(CenterSmall, OnCenterSmall));
+ }
+
+ private void OnIncreaseLarge(object sender, ExecutedRoutedEventArgs e) => (sender as RangeSlider)?.OnIncreaseLarge();
+
+ private void OnIncreaseSmall(object sender, ExecutedRoutedEventArgs e) => (sender as RangeSlider)?.OnIncreaseSmall();
+
+ private void OnDecreaseLarge(object sender, ExecutedRoutedEventArgs e) => (sender as RangeSlider)?.OnDecreaseLarge();
+
+ private void OnDecreaseSmall(object sender, ExecutedRoutedEventArgs e) => (sender as RangeSlider)?.OnDecreaseSmall();
+
+ private void OnCenterLarge(object sender, ExecutedRoutedEventArgs e) => (sender as RangeSlider)?.OnCenterLarge(e.Parameter);
+
+ private void OnCenterSmall(object sender, ExecutedRoutedEventArgs e) => (sender as RangeSlider)?.OnCenterSmall(e.Parameter);
+
+ protected virtual void OnIncreaseLarge() => MoveToNextTick(LargeChange, false);
+
+ protected virtual void OnIncreaseSmall() => MoveToNextTick(LargeChange, false);
+
+ protected virtual void OnDecreaseLarge() => MoveToNextTick(-LargeChange, true);
+
+ protected virtual void OnDecreaseSmall() => MoveToNextTick(-LargeChange, true);
+
+ protected virtual void OnCenterLarge(object parameter) => MoveToNextTick(LargeChange, false, true);
+
+ protected virtual void OnCenterSmall(object parameter) => MoveToNextTick(LargeChange, false, true);
+
+ public static RoutedCommand IncreaseLarge { get; private set; }
+
+ public static RoutedCommand IncreaseSmall { get; private set; }
+
+ public static RoutedCommand DecreaseLarge { get; private set; }
+
+ public static RoutedCommand DecreaseSmall { get; private set; }
+
+ public static RoutedCommand CenterLarge { get; private set; }
+
+ public static RoutedCommand CenterSmall { get; private set; }
+
+ private static void InitializeCommands()
+ {
+ IncreaseLarge = new RoutedCommand(nameof(IncreaseLarge), typeof(RangeSlider));
+ IncreaseSmall = new RoutedCommand(nameof(IncreaseSmall), typeof(RangeSlider));
+
+ DecreaseLarge = new RoutedCommand(nameof(DecreaseLarge), typeof(RangeSlider));
+ DecreaseSmall = new RoutedCommand(nameof(DecreaseSmall), typeof(RangeSlider));
+
+ CenterLarge = new RoutedCommand(nameof(CenterLarge), typeof(RangeSlider));
+ CenterSmall = new RoutedCommand(nameof(CenterSmall), typeof(RangeSlider));
+ }
+
+ public override void OnApplyTemplate()
+ {
+ _thumbCurrent = null;
+
+ base.OnApplyTemplate();
+
+ _track = GetTemplateChild(ElementTrack) as RangeTrack;
+
+ if (_autoToolTipStart != null)
+ {
+ _autoToolTipStart.PlacementTarget = _track?.ThumbStart;
+ }
+
+ if (_autoToolTipEnd != null)
+ {
+ _autoToolTipEnd.PlacementTarget = _track?.ThumbEnd;
+ }
+ }
+
+ public static readonly DependencyProperty OrientationProperty = DependencyProperty.Register(
+ "Orientation", typeof(Orientation), typeof(RangeSlider), new PropertyMetadata(default(Orientation)));
+
+ public Orientation Orientation
+ {
+ get => (Orientation)GetValue(OrientationProperty);
+ set => SetValue(OrientationProperty, value);
+ }
+
+ public static readonly DependencyProperty IsDirectionReversedProperty = DependencyProperty.Register(
+ "IsDirectionReversed", typeof(bool), typeof(RangeSlider), new PropertyMetadata(ValueBoxes.FalseBox));
+
+ public bool IsDirectionReversed
+ {
+ get => (bool)GetValue(IsDirectionReversedProperty);
+ set => SetValue(IsDirectionReversedProperty, value);
+ }
+
+ public static readonly DependencyProperty DelayProperty = RepeatButton.DelayProperty.AddOwner(typeof(RangeSlider), new FrameworkPropertyMetadata(GetKeyboardDelay()));
+
+ public int Delay
+ {
+ get => (int)GetValue(DelayProperty);
+ set => SetValue(DelayProperty, value);
+ }
+
+ internal static int GetKeyboardDelay()
+ {
+ var delay = SystemParameters.KeyboardDelay;
+ if (delay < 0 || delay > 3)
+ delay = 0;
+ return (delay + 1) * 250;
+ }
+
+ public static readonly DependencyProperty IntervalProperty = RepeatButton.IntervalProperty.AddOwner(typeof(RangeSlider), new FrameworkPropertyMetadata(GetKeyboardSpeed()));
+
+ public int Interval
+ {
+ get => (int)GetValue(IntervalProperty);
+ set => SetValue(IntervalProperty, value);
+ }
+
+ internal static int GetKeyboardSpeed()
+ {
+ var speed = SystemParameters.KeyboardSpeed;
+ if (speed < 0 || speed > 31)
+ speed = 31;
+ return (31 - speed) * (400 - 1000 / 30) / 31 + 1000 / 30;
+ }
+
+ public static readonly DependencyProperty AutoToolTipPlacementProperty = DependencyProperty.Register(
+ "AutoToolTipPlacement", typeof(AutoToolTipPlacement), typeof(RangeSlider), new PropertyMetadata(default(AutoToolTipPlacement)));
+
+ public AutoToolTipPlacement AutoToolTipPlacement
+ {
+ get => (AutoToolTipPlacement)GetValue(AutoToolTipPlacementProperty);
+ set => SetValue(AutoToolTipPlacementProperty, value);
+ }
+
+ public static readonly DependencyProperty AutoToolTipPrecisionProperty = DependencyProperty.Register(
+ "AutoToolTipPrecision", typeof(int), typeof(RangeSlider), new PropertyMetadata(ValueBoxes.Int0Box),
+ ValidateHelper.IsInRangeOfPosIntIncludeZero);
+
+ public int AutoToolTipPrecision
+ {
+ get => (int)GetValue(AutoToolTipPrecisionProperty);
+ set => SetValue(AutoToolTipPrecisionProperty, value);
+ }
+
+ public static readonly DependencyProperty IsSnapToTickEnabledProperty = DependencyProperty.Register(
+ "IsSnapToTickEnabled", typeof(bool), typeof(RangeSlider), new PropertyMetadata(ValueBoxes.FalseBox));
+
+ public bool IsSnapToTickEnabled
+ {
+ get => (bool)GetValue(IsSnapToTickEnabledProperty);
+ set => SetValue(IsSnapToTickEnabledProperty, value);
+ }
+
+ public static readonly DependencyProperty TickPlacementProperty = DependencyProperty.Register(
+ "TickPlacement", typeof(TickPlacement), typeof(RangeSlider), new PropertyMetadata(default(TickPlacement)));
+
+ public TickPlacement TickPlacement
+ {
+ get => (TickPlacement)GetValue(TickPlacementProperty);
+ set => SetValue(TickPlacementProperty, value);
+ }
+
+ public static readonly DependencyProperty TickFrequencyProperty = DependencyProperty.Register(
+ "TickFrequency", typeof(double), typeof(RangeSlider), new PropertyMetadata(ValueBoxes.Double1Box),
+ ValidateHelper.IsInRangeOfPosDoubleIncludeZero);
+
+ public double TickFrequency
+ {
+ get => (double)GetValue(TickFrequencyProperty);
+ set => SetValue(TickFrequencyProperty, value);
+ }
+
+ public static readonly DependencyProperty TicksProperty = DependencyProperty.Register(
+ "Ticks", typeof(DoubleCollection), typeof(RangeSlider), new PropertyMetadata(new DoubleCollection()));
+
+ public DoubleCollection Ticks
+ {
+ get => (DoubleCollection)GetValue(TicksProperty);
+ set => SetValue(TicksProperty, value);
+ }
+
+ public static readonly DependencyProperty IsMoveToPointEnabledProperty = DependencyProperty.Register(
+ "IsMoveToPointEnabled", typeof(bool), typeof(RangeSlider), new PropertyMetadata(ValueBoxes.FalseBox));
+
+ public bool IsMoveToPointEnabled
+ {
+ get => (bool)GetValue(IsMoveToPointEnabledProperty);
+ set => SetValue(IsMoveToPointEnabledProperty, value);
+ }
+
+ protected override void OnPreviewMouseLeftButtonDown(MouseButtonEventArgs e)
+ {
+ if (IsMoveToPointEnabled && _track.ThumbStart != null && !_track.ThumbStart.IsMouseOver && _track.ThumbEnd != null && !_track.ThumbEnd.IsMouseOver)
+ {
+ // Here we need to determine whether it's closer to the starting point or the end point.
+ var pt = e.MouseDevice.GetPosition(_track);
+ UpdateValue(pt);
+ e.Handled = true;
+ }
+
+ base.OnPreviewMouseLeftButtonDown(e);
+ }
+
+ private void MoveToNextTick(double direction, bool isStart, bool isCenter = false, object parameter = null)
+ {
+ if (MathHelper.AreClose(direction, 0)) return;
+
+ if (isCenter)
+ {
+ if (parameter == null)
+ {
+ var pt = Mouse.GetPosition(_track);
+ var newValue = _track.ValueFromPoint(pt);
+ if (ValidateHelper.IsInRangeOfDouble(newValue))
+ {
+ var dir = (ValueStart + ValueEnd) / 2 > newValue;
+ if (!dir)
+ {
+ isStart = false;
+ direction = -Math.Abs(direction);
+ }
+ else
+ {
+ isStart = true;
+ }
+ }
+ }
+
+ if (parameter is bool parameterValue)
+ {
+ isStart = parameterValue;
+ }
+ }
+
+ var value = isStart ? ValueStart : ValueEnd;
+ var next = SnapToTick(Math.Max(Minimum, Math.Min(Maximum, value + direction)));
+ var greaterThan = direction > 0;
+
+ // If the snapping brought us back to value, find the next tick point
+ if (MathHelper.AreClose(next, value) &&
+ !(greaterThan && MathHelper.AreClose(value, Maximum)) &&
+ !(!greaterThan && MathHelper.AreClose(value, Minimum)))
+ {
+ // If ticks collection is available, use it.
+ // Note that ticks may be unsorted.
+ if (Ticks != null && Ticks.Count > 0)
+ {
+ foreach (var tick in Ticks)
+ {
+ // Find the smallest tick greater than value or the largest tick less than value
+ if (greaterThan && MathHelper.GreaterThan(tick, value) && (MathHelper.LessThan(tick, next) || MathHelper.AreClose(next, value))
+ || !greaterThan && MathHelper.LessThan(tick, value) && (MathHelper.GreaterThan(tick, next) || MathHelper.AreClose(next, value)))
+ {
+ next = tick;
+ }
+ }
+ }
+ else if (MathHelper.GreaterThan(TickFrequency, 0.0))
+ {
+ // Find the current tick we are at
+ var tickNumber = Math.Round((value - Minimum) / TickFrequency);
+
+ if (greaterThan)
+ tickNumber += 1.0;
+ else
+ tickNumber -= 1.0;
+
+ next = Minimum + tickNumber * TickFrequency;
+ }
+ }
+
+ // Update if we've found a better value
+ if (!MathHelper.AreClose(next, value))
+ {
+ SetCurrentValue(isStart ? ValueStartProperty : ValueEndProperty, next);
+ }
+ }
+
+ private double SnapToTick(double value)
+ {
+ if (!IsSnapToTickEnabled) return value;
+
+ var previous = Minimum;
+ var next = Maximum;
+
+ if (Ticks != null && Ticks.Count > 0)
+ {
+ foreach (var tick in Ticks)
+ {
+ if (MathHelper.AreClose(tick, value))
+ {
+ return value;
+ }
+
+ if (MathHelper.LessThan(tick, value) && MathHelper.GreaterThan(tick, previous))
+ {
+ previous = tick;
+ }
+ else if (MathHelper.GreaterThan(tick, value) && MathHelper.LessThan(tick, next))
+ {
+ next = tick;
+ }
+ }
+ }
+ else if (MathHelper.GreaterThan(TickFrequency, 0.0))
+ {
+ previous = Minimum + Math.Round((value - Minimum) / TickFrequency) * TickFrequency;
+ next = Math.Min(Maximum, previous + TickFrequency);
+ }
+
+ return MathHelper.GreaterThanOrClose(value, (previous + next) * 0.5) ? next : previous;
+ }
+
+ private void UpdateValue(Point point)
+ {
+ var newValue = _track.ValueFromPoint(point);
+ if (ValidateHelper.IsInRangeOfDouble(newValue))
+ {
+ var isStart = (ValueStart + ValueEnd) / 2 > newValue;
+ UpdateValue(newValue, isStart);
+ }
+ }
+
+ private void UpdateValue(double value, bool isStart)
+ {
+ var snappedValue = SnapToTick(value);
+
+ if (isStart)
+ {
+ if (!MathHelper.AreClose(snappedValue, ValueStart))
+ {
+ var start = Math.Max(Minimum, Math.Min(Maximum, snappedValue));
+ if (start > ValueEnd)
+ {
+ SetCurrentValue(ValueEndProperty, start);
+ _track.ThumbStart.CancelDrag();
+ _track.ThumbEnd.StartDrag();
+ _thumbCurrent = _track.ThumbEnd;
+ }
+ else
+ {
+ SetCurrentValue(ValueStartProperty, start);
+ }
+ }
+ }
+ else
+ {
+ if (!MathHelper.AreClose(snappedValue, ValueEnd))
+ {
+ var end = Math.Max(Minimum, Math.Min(Maximum, snappedValue));
+ if (end < ValueStart)
+ {
+ SetCurrentValue(ValueStartProperty, end);
+ _track.ThumbEnd.CancelDrag();
+ _track.ThumbStart.StartDrag();
+ _thumbCurrent = _track.ThumbStart;
+ }
+ else
+ {
+ SetCurrentValue(ValueEndProperty, end);
+ }
+ }
+ }
+ }
+
+ private static void OnThumbDragStarted(object sender, DragStartedEventArgs e) => (sender as RangeSlider)?.OnThumbDragStarted(e);
+
+ protected virtual void OnThumbDragStarted(DragStartedEventArgs e)
+ {
+ // Show AutoToolTip if needed.
+
+ if (!(e.OriginalSource is RangeThumb thumb)) return;
+ _thumbCurrent = thumb;
+ _originThumbPoint = Mouse.GetPosition(_thumbCurrent);
+ _thumbCurrent.StartDrag();
+
+ if (AutoToolTipPlacement == AutoToolTipPlacement.None)
+ {
+ return;
+ }
+
+ var isStart = thumb.Equals(_track.ThumbStart);
+ if (!isStart)
+ {
+ if (!thumb.Equals(_track.ThumbEnd)) return;
+ }
+
+ // Save original tooltip
+ _thumbOriginalToolTip = thumb.ToolTip;
+ OnThumbDragStarted(isStart ? _autoToolTipStart : _autoToolTipEnd, isStart);
+ }
+
+ private void OnThumbDragStarted(ToolTip toolTip, bool isStart)
+ {
+ if (toolTip == null)
+ {
+ toolTip = new ToolTip
+ {
+ Placement = PlacementMode.Custom,
+ PlacementTarget = isStart ? _track.ThumbStart : _track.ThumbEnd,
+ CustomPopupPlacementCallback = AutoToolTipCustomPlacementCallback
+ };
+ }
+
+ if (isStart)
+ {
+ _track.ThumbStart.ToolTip = toolTip;
+ }
+ else
+ {
+ _track.ThumbEnd.ToolTip = toolTip;
+ }
+ toolTip.Content = GetAutoToolTipNumber(isStart);
+ toolTip.IsOpen = true;
+ }
+
+ private CustomPopupPlacement[] AutoToolTipCustomPlacementCallback(Size popupSize, Size targetSize, Point offset)
+ {
+ switch (AutoToolTipPlacement)
+ {
+ case AutoToolTipPlacement.TopLeft:
+ if (Orientation == Orientation.Horizontal)
+ {
+ // Place popup at top of thumb
+ return new[]{new CustomPopupPlacement(
+ new Point((targetSize.Width - popupSize.Width) * 0.5, -popupSize.Height),
+ PopupPrimaryAxis.Horizontal)
+ };
+ }
+ else
+ {
+ // Place popup at left of thumb
+ return new[] {
+ new CustomPopupPlacement(
+ new Point(-popupSize.Width, (targetSize.Height - popupSize.Height) * 0.5),
+ PopupPrimaryAxis.Vertical)
+ };
+ }
+
+ case AutoToolTipPlacement.BottomRight:
+ if (Orientation == Orientation.Horizontal)
+ {
+ // Place popup at bottom of thumb
+ return new[] {
+ new CustomPopupPlacement(
+ new Point((targetSize.Width - popupSize.Width) * 0.5, targetSize.Height) ,
+ PopupPrimaryAxis.Horizontal)
+ };
+
+ }
+ else
+ {
+ // Place popup at right of thumb
+ return new[] {
+ new CustomPopupPlacement(
+ new Point(targetSize.Width, (targetSize.Height - popupSize.Height) * 0.5),
+ PopupPrimaryAxis.Vertical)
+ };
+ }
+
+ default:
+ return new CustomPopupPlacement[] { };
+ }
+ }
+
+ private string GetAutoToolTipNumber(bool isStart)
+ {
+ var format = (NumberFormatInfo)NumberFormatInfo.CurrentInfo.Clone();
+ format.NumberDecimalDigits = AutoToolTipPrecision;
+ return isStart ? ValueStart.ToString("N", format) : ValueEnd.ToString("N", format);
+ }
+
+ private static void OnThumbDragDelta(object sender, DragDeltaEventArgs e) => (sender as RangeSlider)?.OnThumbDragDelta(e);
+
+ protected virtual void OnThumbDragDelta(DragDeltaEventArgs e)
+ {
+ if (!(e.OriginalSource is Thumb thumb)) return;
+ var isStart = thumb.Equals(_track.ThumbStart);
+ if (!isStart)
+ {
+ if (!thumb.Equals(_track.ThumbEnd)) return;
+ }
+
+ // Convert to Track's co-ordinate
+ OnThumbDragDelta(_track, isStart, e);
+ }
+
+ private void OnThumbDragDelta(RangeTrack track, bool isStart, DragDeltaEventArgs e)
+ {
+ if (track == null || track.ThumbStart == null | _track.ThumbEnd == null) return;
+
+ var newValue = (isStart ? ValueStart : ValueEnd) + track.ValueFromDistance(e.HorizontalChange, e.VerticalChange);
+ Console.WriteLine(newValue);
+ if (ValidateHelper.IsInRangeOfDouble(newValue))
+ {
+ UpdateValue(newValue, isStart);
+ }
+
+ // Show AutoToolTip if needed
+ if (AutoToolTipPlacement != AutoToolTipPlacement.None)
+ {
+ var toolTip = (isStart ? _autoToolTipStart : _autoToolTipEnd) ?? new ToolTip();
+
+ toolTip.Content = GetAutoToolTipNumber(isStart);
+
+ var thumb = isStart ? _track.ThumbStart : _track.ThumbEnd;
+
+ if (!Equals(thumb.ToolTip, toolTip))
+ {
+ thumb.ToolTip = toolTip;
+ }
+
+ if (!toolTip.IsOpen)
+ {
+ toolTip.IsOpen = true;
+ }
+ }
+ }
+
+ private static void OnThumbDragCompleted(object sender, DragCompletedEventArgs e) => (sender as RangeSlider)?.OnThumbDragCompleted(e);
+
+ protected virtual void OnThumbDragCompleted(DragCompletedEventArgs e)
+ {
+ // Show AutoToolTip if needed.
+
+ if (!(e.OriginalSource is Thumb thumb) || AutoToolTipPlacement == AutoToolTipPlacement.None)
+ {
+ return;
+ }
+
+ var isStart = thumb.Equals(_track.ThumbStart);
+ if (!isStart)
+ {
+ if (!thumb.Equals(_track.ThumbEnd)) return;
+ }
+
+ var toolTip = isStart ? _autoToolTipStart : _autoToolTipEnd;
+ if (toolTip != null)
+ {
+ toolTip.IsOpen = false;
+ }
+
+ thumb.ToolTip = _thumbOriginalToolTip;
+ }
+
+ private static void OnMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
+ {
+ if (e.ChangedButton != MouseButton.Left) return;
+
+ var slider = (RangeSlider)sender;
+
+ // When someone click on the Slider's part, and it's not focusable
+ // Slider need to take the focus in order to process keyboard correctly
+ if (!slider.IsKeyboardFocusWithin)
+ {
+ e.Handled = slider.Focus() || e.Handled;
+ }
+
+ if (slider._track.ThumbStart.IsMouseOver)
+ {
+ slider._track.ThumbStart.StartDrag();
+ slider._thumbCurrent = slider._track.ThumbStart;
+ }
+
+ if (slider._track.ThumbEnd.IsMouseOver)
+ {
+ slider._track.ThumbEnd.StartDrag();
+ slider._thumbCurrent = slider._track.ThumbEnd;
+ }
+ }
+
+ protected override void OnMouseMove(MouseEventArgs e)
+ {
+ Console.WriteLine(e.GetPosition(this));
+ if (_thumbCurrent == null) return;
+ if (e.MouseDevice.LeftButton != MouseButtonState.Pressed) return;
+
+ if (!_thumbCurrent.IsDragging) return;
+
+ var thumbCoordPosition = e.GetPosition(_thumbCurrent);
+ var screenCoordPosition = PointFromScreen(thumbCoordPosition);
+ if (screenCoordPosition != _previousScreenCoordPosition)
+ {
+ _previousScreenCoordPosition = screenCoordPosition;
+ _thumbCurrent.RaiseEvent(new DragDeltaEventArgs(thumbCoordPosition.X - _originThumbPoint.X,
+ thumbCoordPosition.Y - _originThumbPoint.Y));
+ }
+ }
+
+ protected override void OnPreviewMouseLeftButtonUp(MouseButtonEventArgs e)
+ {
+ base.OnPreviewMouseLeftButtonUp(e);
+
+ _thumbCurrent = null;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Shared/HandyControl_Shared/Controls/Slider/RangeSlider/RangeThumb.cs b/src/Shared/HandyControl_Shared/Controls/Slider/RangeSlider/RangeThumb.cs
new file mode 100644
index 00000000..fee42007
--- /dev/null
+++ b/src/Shared/HandyControl_Shared/Controls/Slider/RangeSlider/RangeThumb.cs
@@ -0,0 +1,46 @@
+using System;
+using System.Windows;
+using System.Windows.Controls.Primitives;
+using System.Windows.Input;
+
+namespace HandyControl.Controls
+{
+ public class RangeThumb : Thumb
+ {
+ public static readonly DependencyProperty ContentProperty = DependencyProperty.Register(
+ "Content", typeof(object), typeof(RangeThumb), new PropertyMetadata(default(object)));
+
+ public object Content
+ {
+ get => GetValue(ContentProperty);
+ set => SetValue(ContentProperty, value);
+ }
+
+ protected override void OnMouseMove(MouseEventArgs e)
+ {
+
+ }
+
+ public void StartDrag()
+ {
+ IsDragging = true;
+ Focus();
+ CaptureMouse();
+ RaiseEvent(new MouseButtonEventArgs(Mouse.PrimaryDevice, Environment.TickCount, MouseButton.Left)
+ {
+ RoutedEvent = PreviewMouseLeftButtonDownEvent,
+ Source = this
+ });
+ }
+
+ public new void CancelDrag()
+ {
+ base.CancelDrag();
+
+ RaiseEvent(new MouseButtonEventArgs(Mouse.PrimaryDevice, Environment.TickCount, MouseButton.Left)
+ {
+ RoutedEvent = PreviewMouseLeftButtonUpEvent
+ });
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Shared/HandyControl_Shared/Controls/Slider/RangeSlider/RangeTrack.cs b/src/Shared/HandyControl_Shared/Controls/Slider/RangeSlider/RangeTrack.cs
new file mode 100644
index 00000000..99e4dfad
--- /dev/null
+++ b/src/Shared/HandyControl_Shared/Controls/Slider/RangeSlider/RangeTrack.cs
@@ -0,0 +1,444 @@
+// Adapted from https://referencesource.microsoft.com/#PresentationFramework/src/Framework/System/Windows/Controls/Primitives/Track.cs
+
+using System;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Controls.Primitives;
+using System.Windows.Input;
+using System.Windows.Media;
+using HandyControl.Data;
+
+namespace HandyControl.Controls
+{
+ public class RangeTrack : FrameworkElement
+ {
+ private RepeatButton _increaseButton;
+
+ private RepeatButton _centerButton;
+
+ private RepeatButton _decreaseButton;
+
+ private RangeThumb _thumbStart;
+
+ private RangeThumb _thumbEnd;
+
+ private Visual[] _visualChildren;
+
+ private double Density { get; set; } = double.NaN;
+
+ private double ThumbStartCenterOffset { get; set; } = double.NaN;
+
+ public RepeatButton DecreaseRepeatButton
+ {
+ get => _decreaseButton;
+ set
+ {
+ if (Equals(_increaseButton, value) || Equals(_centerButton, value))
+ {
+ throw new NotSupportedException("SameButtons");
+ }
+ UpdateComponent(_decreaseButton, value);
+ _decreaseButton = value;
+
+ if (_decreaseButton != null)
+ {
+ CommandManager.InvalidateRequerySuggested(); // Should post an idle queue item to update IsEnabled on button
+ }
+ }
+ }
+
+ public RepeatButton CenterRepeatButton
+ {
+ get => _centerButton;
+ set
+ {
+ if (Equals(_increaseButton, value) || Equals(_decreaseButton, value))
+ {
+ throw new NotSupportedException("SameButtons");
+ }
+ UpdateComponent(_centerButton, value);
+ _centerButton = value;
+
+ if (_centerButton != null)
+ {
+ CommandManager.InvalidateRequerySuggested(); // Should post an idle queue item to update IsEnabled on button
+ }
+ }
+ }
+
+ public RepeatButton IncreaseRepeatButton
+ {
+ get => _increaseButton;
+ set
+ {
+ if (Equals(_decreaseButton, value) || Equals(_centerButton, value))
+ {
+ throw new NotSupportedException("SameButtons");
+ }
+ UpdateComponent(_increaseButton, value);
+ _increaseButton = value;
+
+ if (_increaseButton != null)
+ {
+ CommandManager.InvalidateRequerySuggested(); // Should post an idle queue item to update IsEnabled on button
+ }
+ }
+ }
+
+ public RangeThumb ThumbStart
+ {
+ get => _thumbStart;
+ set
+ {
+ UpdateComponent(_thumbStart, value);
+ _thumbStart = value;
+ }
+ }
+
+ public RangeThumb ThumbEnd
+ {
+ get => _thumbEnd;
+ set
+ {
+ UpdateComponent(_thumbEnd, value);
+ _thumbEnd = value;
+ }
+ }
+
+ static RangeTrack()
+ {
+ IsEnabledProperty.OverrideMetadata(typeof(RangeTrack), new UIPropertyMetadata(OnIsEnabledChanged));
+ }
+
+ public static readonly DependencyProperty OrientationProperty = DependencyProperty.Register(
+ "Orientation", typeof(Orientation), typeof(RangeTrack),
+ new FrameworkPropertyMetadata(default(Orientation), FrameworkPropertyMetadataOptions.AffectsMeasure));
+
+ public Orientation Orientation
+ {
+ get => (Orientation) GetValue(OrientationProperty);
+ set => SetValue(OrientationProperty, value);
+ }
+
+ public static readonly DependencyProperty MinimumProperty = DependencyProperty.Register(
+ "Minimum", typeof(double), typeof(RangeTrack),
+ new FrameworkPropertyMetadata(ValueBoxes.Double0Box, FrameworkPropertyMetadataOptions.AffectsArrange));
+
+ public double Minimum
+ {
+ get => (double) GetValue(MinimumProperty);
+ set => SetValue(MinimumProperty, value);
+ }
+
+ public static readonly DependencyProperty MaximumProperty = DependencyProperty.Register(
+ "Maximum", typeof(double), typeof(RangeTrack),
+ new FrameworkPropertyMetadata(ValueBoxes.Double1Box, FrameworkPropertyMetadataOptions.AffectsArrange));
+
+ public double Maximum
+ {
+ get => (double) GetValue(MaximumProperty);
+ set => SetValue(MaximumProperty, value);
+ }
+
+ public static readonly DependencyProperty ValueStartProperty = DependencyProperty.Register(
+ "ValueStart", typeof(double), typeof(RangeTrack),
+ new FrameworkPropertyMetadata(ValueBoxes.Double0Box,
+ FrameworkPropertyMetadataOptions.BindsTwoWayByDefault |
+ FrameworkPropertyMetadataOptions.AffectsArrange));
+
+ public double ValueStart
+ {
+ get => (double) GetValue(ValueStartProperty);
+ set => SetValue(ValueStartProperty, value);
+ }
+
+ public static readonly DependencyProperty ValueEndProperty = DependencyProperty.Register(
+ "ValueEnd", typeof(double), typeof(RangeTrack),
+ new FrameworkPropertyMetadata(ValueBoxes.Double0Box,
+ FrameworkPropertyMetadataOptions.BindsTwoWayByDefault |
+ FrameworkPropertyMetadataOptions.AffectsArrange));
+
+ public double ValueEnd
+ {
+ get => (double) GetValue(ValueEndProperty);
+ set => SetValue(ValueEndProperty, value);
+ }
+
+ public static readonly DependencyProperty IsDirectionReversedProperty = DependencyProperty.Register(
+ "IsDirectionReversed", typeof(bool), typeof(RangeTrack), new PropertyMetadata(ValueBoxes.FalseBox));
+
+ public bool IsDirectionReversed
+ {
+ get => (bool) GetValue(IsDirectionReversedProperty);
+ set => SetValue(IsDirectionReversedProperty, value);
+ }
+
+ protected override Visual GetVisualChild(int index)
+ {
+ if (_visualChildren?[index] == null)
+ {
+ // ReSharper disable once UseNameofExpression
+ // ReSharper disable once LocalizableElement
+ throw new ArgumentOutOfRangeException("index", index, "ArgumentOutOfRange");
+ }
+ return _visualChildren[index];
+ }
+
+ protected override Size MeasureOverride(Size availableSize)
+ {
+ var desiredSize = new Size();
+
+ // Only measure thumb
+ // Repeat buttons will be sized based on thumb
+ if (_thumbStart != null)
+ {
+ _thumbStart.Measure(availableSize);
+ desiredSize = _thumbStart.DesiredSize;
+ }
+
+ if (_thumbEnd != null)
+ {
+ _thumbEnd.Measure(availableSize);
+ desiredSize = new Size(Math.Max(_thumbEnd.DesiredSize.Width, desiredSize.Width),
+ Math.Max(_thumbEnd.DesiredSize.Height, desiredSize.Height));
+ }
+
+ return desiredSize;
+ }
+
+ private static void CoerceLength(ref double componentLength, double trackLength)
+ {
+ if (componentLength < 0)
+ {
+ componentLength = 0;
+ }
+ else if (componentLength > trackLength || double.IsNaN(componentLength))
+ {
+ componentLength = trackLength;
+ }
+ }
+
+ protected override Size ArrangeOverride(Size arrangeSize)
+ {
+ var isVertical = Orientation == Orientation.Vertical;
+
+ ComputeLengths(arrangeSize, isVertical, out var decreaseButtonLength, out var centerButtonLength,
+ out var increaseButtonLength, out var thumbStartLength, out var thumbEndLength);
+
+ var offset = new Point();
+ var pieceSize = arrangeSize;
+ var isDirectionReversed = IsDirectionReversed;
+
+ if (isVertical)
+ {
+ CoerceLength(ref decreaseButtonLength, arrangeSize.Height);
+ CoerceLength(ref centerButtonLength, arrangeSize.Height);
+ CoerceLength(ref increaseButtonLength, arrangeSize.Height);
+ CoerceLength(ref thumbStartLength, arrangeSize.Height);
+ CoerceLength(ref thumbEndLength, arrangeSize.Height);
+
+ offset.Y = isDirectionReversed ? decreaseButtonLength + thumbEndLength + centerButtonLength + thumbStartLength : 0;
+ pieceSize.Height = increaseButtonLength;
+
+ IncreaseRepeatButton?.Arrange(new Rect(offset, pieceSize));
+
+ offset.Y = isDirectionReversed ? decreaseButtonLength + thumbEndLength : increaseButtonLength + thumbStartLength;
+ pieceSize.Height = centerButtonLength;
+
+ CenterRepeatButton?.Arrange(new Rect(offset, pieceSize));
+
+ offset.Y = isDirectionReversed ? 0 : increaseButtonLength + thumbStartLength + centerButtonLength + thumbEndLength;
+ pieceSize.Height = decreaseButtonLength;
+
+ DecreaseRepeatButton?.Arrange(new Rect(offset, pieceSize));
+
+ offset.Y = isDirectionReversed
+ ? decreaseButtonLength + thumbEndLength + centerButtonLength
+ : increaseButtonLength + thumbStartLength + centerButtonLength;
+ pieceSize.Height = thumbStartLength;
+
+ ThumbStart?.Arrange(new Rect(offset, pieceSize));
+ ThumbStartCenterOffset = offset.Y + thumbStartLength * 0.5;
+
+ offset.Y = isDirectionReversed ? decreaseButtonLength : increaseButtonLength;
+ pieceSize.Height = thumbEndLength;
+
+ ThumbEnd?.Arrange(new Rect(offset, pieceSize));
+ }
+ else
+ {
+ CoerceLength(ref decreaseButtonLength, arrangeSize.Width);
+ CoerceLength(ref centerButtonLength, arrangeSize.Width);
+ CoerceLength(ref increaseButtonLength, arrangeSize.Width);
+ CoerceLength(ref thumbStartLength, arrangeSize.Width);
+ CoerceLength(ref thumbEndLength, arrangeSize.Width);
+
+ offset.X = isDirectionReversed ? 0 : decreaseButtonLength + thumbEndLength + centerButtonLength + thumbStartLength;
+ pieceSize.Width = increaseButtonLength;
+
+ IncreaseRepeatButton?.Arrange(new Rect(offset, pieceSize));
+
+ offset.X = isDirectionReversed ? increaseButtonLength + thumbStartLength : decreaseButtonLength + thumbEndLength;
+ pieceSize.Width = centerButtonLength;
+
+ CenterRepeatButton?.Arrange(new Rect(offset, pieceSize));
+
+ offset.X = isDirectionReversed ? increaseButtonLength + thumbStartLength + centerButtonLength + thumbEndLength : 0;
+ pieceSize.Width = decreaseButtonLength;
+
+ DecreaseRepeatButton?.Arrange(new Rect(offset, pieceSize));
+
+ offset.X = isDirectionReversed ? increaseButtonLength : decreaseButtonLength;
+ pieceSize.Width = thumbStartLength;
+
+ ThumbStart?.Arrange(new Rect(offset, pieceSize));
+ ThumbStartCenterOffset = offset.X + thumbStartLength * 0.5;
+
+ offset.X = isDirectionReversed
+ ? increaseButtonLength + thumbStartLength + centerButtonLength
+ : decreaseButtonLength + thumbEndLength + centerButtonLength;
+ pieceSize.Width = thumbEndLength;
+
+ ThumbEnd?.Arrange(new Rect(offset, pieceSize));
+ }
+
+ return arrangeSize;
+ }
+
+ private void ComputeLengths(Size arrangeSize, bool isVertical, out double decreaseButtonLength,
+ out double centerButtonLength, out double increaseButtonLength, out double thumbStartLength,
+ out double thumbEndLength)
+ {
+ var min = Minimum;
+ var range = Math.Max(0.0, Maximum - min);
+ var offsetStart = Math.Min(range, ValueStart - min);
+ var offsetEnd = Math.Min(range, ValueEnd - min);
+
+ double trackLength;
+
+ // Compute thumb size
+ if (isVertical)
+ {
+ trackLength = arrangeSize.Height;
+ thumbStartLength = _thumbStart?.DesiredSize.Height ?? 0;
+ thumbEndLength = _thumbEnd?.DesiredSize.Height ?? 0;
+ }
+ else
+ {
+ trackLength = arrangeSize.Width;
+ thumbStartLength = _thumbStart?.DesiredSize.Width ?? 0;
+ thumbEndLength = _thumbEnd?.DesiredSize.Width ?? 0;
+ }
+
+ CoerceLength(ref thumbStartLength, trackLength);
+ CoerceLength(ref thumbEndLength, trackLength);
+
+ var remainingTrackLength = trackLength - thumbStartLength - thumbEndLength;
+
+ decreaseButtonLength = remainingTrackLength * offsetStart / range;
+ CoerceLength(ref decreaseButtonLength, remainingTrackLength);
+
+ centerButtonLength = remainingTrackLength * offsetEnd / range - decreaseButtonLength;
+ CoerceLength(ref centerButtonLength, remainingTrackLength);
+
+ increaseButtonLength = remainingTrackLength - decreaseButtonLength - centerButtonLength;
+ CoerceLength(ref increaseButtonLength, remainingTrackLength);
+
+ Density = range / remainingTrackLength;
+ }
+
+ protected override int VisualChildrenCount
+ {
+ get
+ {
+ if (_visualChildren == null) return 0;
+
+ for (int i = 0; i < _visualChildren.Length; i++)
+ {
+ if (_visualChildren[i] == null) return i;
+ }
+
+ return _visualChildren.Length;
+ }
+ }
+
+ private static void OnIsEnabledChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
+ {
+ if ((bool)e.NewValue)
+ {
+ Mouse.Synchronize();
+ }
+ }
+
+ public virtual double ValueFromPoint(Point pt)
+ {
+ double val;
+ // Find distance from center of thumb to given point.
+ if (Orientation == Orientation.Horizontal)
+ {
+ val = ValueStart + ValueFromDistance(pt.X - ThumbStartCenterOffset, pt.Y - RenderSize.Height * 0.5);
+ }
+ else
+ {
+ val = ValueStart + ValueFromDistance(pt.X - RenderSize.Width * 0.5, pt.Y - ThumbStartCenterOffset);
+ }
+ return Math.Max(Minimum, Math.Min(Maximum, val));
+ }
+
+ public virtual double ValueFromDistance(double horizontal, double vertical)
+ {
+ double scale = IsDirectionReversed ? -1 : 1;
+ return Orientation == Orientation.Horizontal
+ ? scale * horizontal * Density
+ : -1 * scale * vertical * Density;
+ }
+
+ private void UpdateComponent(Control oldValue, Control newValue)
+ {
+ if (oldValue != newValue)
+ {
+ if (_visualChildren == null)
+ {
+ _visualChildren = new Visual[5];
+ }
+
+ if (oldValue != null)
+ {
+ // notify the visual layer that the old component has been removed.
+ RemoveVisualChild(oldValue);
+ }
+
+ // Remove the old value from our z index list and add new value to end
+ int i = 0;
+ while (i < 5)
+ {
+ // Array isn't full, break
+ if (_visualChildren[i] == null)
+ break;
+
+ // found the old value
+ if (_visualChildren[i] == oldValue)
+ {
+ // Move values down until end of array or a null element
+ while (i < 4 && _visualChildren[i + 1] != null)
+ {
+ _visualChildren[i] = _visualChildren[i + 1];
+ i++;
+ }
+ }
+ else
+ {
+ i++;
+ }
+ }
+ // Add newValue at end of z-order
+ _visualChildren[i] = newValue;
+
+ AddVisualChild(newValue);
+
+ InvalidateMeasure();
+ InvalidateArrange();
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Shared/HandyControl_Shared/Controls/Slider/RangeSlider/TwoWayRangeBase.cs b/src/Shared/HandyControl_Shared/Controls/Slider/RangeSlider/TwoWayRangeBase.cs
new file mode 100644
index 00000000..7c3b5b5f
--- /dev/null
+++ b/src/Shared/HandyControl_Shared/Controls/Slider/RangeSlider/TwoWayRangeBase.cs
@@ -0,0 +1,181 @@
+// Adapted from https://referencesource.microsoft.com/#PresentationFramework/src/Framework/System/Windows/Controls/Primitives/RangeBase.cs
+
+using HandyControl.Data;
+using HandyControl.Tools;
+using System.Windows;
+using System.Windows.Controls;
+
+namespace HandyControl.Controls
+{
+ public class TwoWayRangeBase : Control
+ {
+ public static readonly DependencyProperty MinimumProperty = DependencyProperty.Register(
+ "Minimum", typeof(double), typeof(TwoWayRangeBase),
+ new PropertyMetadata(ValueBoxes.Double0Box, OnMinimumChanged), ValidateHelper.IsInRangeOfDouble);
+
+ private static void OnMinimumChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
+ {
+ var ctrl = (TwoWayRangeBase)d;
+
+ ctrl.CoerceValue(MaximumProperty);
+ ctrl.CoerceValue(ValueStartProperty);
+ ctrl.CoerceValue(ValueEndProperty);
+ ctrl.OnMinimumChanged((double)e.OldValue, (double)e.NewValue);
+ }
+
+ protected virtual void OnMinimumChanged(double oldMinimum, double newMinimum)
+ {
+ }
+
+ public double Minimum
+ {
+ get => (double)GetValue(MinimumProperty);
+ set => SetValue(MinimumProperty, value);
+ }
+
+ public static readonly DependencyProperty MaximumProperty = DependencyProperty.Register(
+ "Maximum", typeof(double), typeof(TwoWayRangeBase),
+ new PropertyMetadata(ValueBoxes.Double10Box, OnMaximumChanged, CoerceMaximum),
+ ValidateHelper.IsInRangeOfDouble);
+
+ private static object CoerceMaximum(DependencyObject d, object basevalue)
+ {
+ var ctrl = (TwoWayRangeBase)d;
+ var min = ctrl.Minimum;
+ if ((double)basevalue < min)
+ {
+ return min;
+ }
+ return basevalue;
+ }
+
+ private static void OnMaximumChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
+ {
+ var ctrl = (TwoWayRangeBase)d;
+
+ ctrl.CoerceValue(ValueStartProperty);
+ ctrl.CoerceValue(ValueEndProperty);
+ ctrl.OnMaximumChanged((double)e.OldValue, (double)e.NewValue);
+ }
+
+ protected virtual void OnMaximumChanged(double oldMaximum, double newMaximum)
+ {
+ }
+
+ public double Maximum
+ {
+ get => (double)GetValue(MaximumProperty);
+ set => SetValue(MaximumProperty, value);
+ }
+
+ public static readonly DependencyProperty ValueStartProperty = DependencyProperty.Register(
+ "ValueStart", typeof(double), typeof(TwoWayRangeBase),
+ new FrameworkPropertyMetadata(ValueBoxes.Double0Box,
+ FrameworkPropertyMetadataOptions.BindsTwoWayByDefault | FrameworkPropertyMetadataOptions.Journal,
+ OnValueStartChanged, ConstrainToRange), ValidateHelper.IsInRangeOfDouble);
+
+ private static void OnValueStartChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
+ {
+ var ctrl = (TwoWayRangeBase)d;
+ ctrl.OnValueChanged(new TwoWayRange
+ {
+ ValueStart = (double)e.OldValue,
+ ValueEnd = ctrl.ValueEnd
+ }, new TwoWayRange
+ {
+ ValueStart = (double)e.NewValue,
+ ValueEnd = ctrl.ValueEnd
+ });
+ }
+
+ protected virtual void OnValueChanged(TwoWayRange oldValue, TwoWayRange newValue) => RaiseEvent(
+ new RoutedPropertyChangedEventArgs(oldValue, newValue) {RoutedEvent = ValueChangedEvent});
+
+ public double ValueStart
+ {
+ get => (double)GetValue(ValueStartProperty);
+ set => SetValue(ValueStartProperty, value);
+ }
+
+ public static readonly DependencyProperty ValueEndProperty = DependencyProperty.Register(
+ "ValueEnd", typeof(double), typeof(TwoWayRangeBase),
+ new FrameworkPropertyMetadata(ValueBoxes.Double0Box,
+ FrameworkPropertyMetadataOptions.BindsTwoWayByDefault | FrameworkPropertyMetadataOptions.Journal,
+ OnValueEndChanged, ConstrainToRange), ValidateHelper.IsInRangeOfDouble);
+
+ private static void OnValueEndChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
+ {
+ var ctrl = (TwoWayRangeBase)d;
+ ctrl.OnValueChanged(new TwoWayRange
+ {
+ ValueStart = ctrl.ValueStart,
+ ValueEnd = (double)e.OldValue
+ }, new TwoWayRange
+ {
+ ValueStart = ctrl.ValueStart,
+ ValueEnd = (double)e.NewValue
+ });
+ }
+
+ public double ValueEnd
+ {
+ get => (double)GetValue(ValueEndProperty);
+ set => SetValue(ValueEndProperty, value);
+ }
+
+ internal static object ConstrainToRange(DependencyObject d, object value)
+ {
+ var ctrl = (TwoWayRangeBase)d;
+ var min = ctrl.Minimum;
+ var v = (double)value;
+ if (v < min)
+ {
+ return min;
+ }
+
+ var max = ctrl.Maximum;
+ if (v > max)
+ {
+ return max;
+ }
+
+ return value;
+ }
+
+ public static readonly DependencyProperty LargeChangeProperty = DependencyProperty.Register(
+ "LargeChange", typeof(double), typeof(TwoWayRangeBase), new PropertyMetadata(ValueBoxes.Double1Box),
+ ValidateHelper.IsInRangeOfPosDoubleIncludeZero);
+
+ public double LargeChange
+ {
+ get => (double)GetValue(LargeChangeProperty);
+ set => SetValue(LargeChangeProperty, value);
+ }
+
+ public static readonly DependencyProperty SmallChangeProperty = DependencyProperty.Register(
+ "SmallChange", typeof(double), typeof(TwoWayRangeBase), new PropertyMetadata(ValueBoxes.Double01Box),
+ ValidateHelper.IsInRangeOfPosDoubleIncludeZero);
+
+ public double SmallChange
+ {
+ get => (double)GetValue(SmallChangeProperty);
+ set => SetValue(SmallChangeProperty, value);
+ }
+
+ public static readonly RoutedEvent ValueChangedEvent = EventManager.RegisterRoutedEvent("ValueChanged",
+ RoutingStrategy.Bubble, typeof(RoutedPropertyChangedEventHandler), typeof(TwoWayRangeBase));
+
+ public event RoutedPropertyChangedEventHandler ValueChanged
+ {
+ add => AddHandler(ValueChangedEvent, value);
+ remove => RemoveHandler(ValueChangedEvent, value);
+ }
+ }
+
+ public struct TwoWayRange
+ {
+ public double ValueStart { get; set; }
+
+ public double ValueEnd { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/Shared/HandyControl_Shared/Data/ValueBoxes.cs b/src/Shared/HandyControl_Shared/Data/ValueBoxes.cs
index d53cba75..dea64e0b 100644
--- a/src/Shared/HandyControl_Shared/Data/ValueBoxes.cs
+++ b/src/Shared/HandyControl_Shared/Data/ValueBoxes.cs
@@ -11,8 +11,12 @@
internal static object Double0Box = .0;
+ internal static object Double01Box = .1;
+
internal static object Double1Box = 1.0;
+ internal static object Double10Box = 10.0;
+
internal static object Double20Box = 20.0;
internal static object Double100Box = 100.0;
diff --git a/src/Shared/HandyControl_Shared/HandyControl_Shared.projitems b/src/Shared/HandyControl_Shared/HandyControl_Shared.projitems
index ca096912..4b26b7e4 100644
--- a/src/Shared/HandyControl_Shared/HandyControl_Shared.projitems
+++ b/src/Shared/HandyControl_Shared/HandyControl_Shared.projitems
@@ -18,6 +18,9 @@
+
+
+
@@ -85,10 +88,10 @@
-
-
+
+
-
+
@@ -333,6 +336,10 @@
Designer
MSBuild:Compile
+
+ Designer
+ MSBuild:Compile
+
Designer
MSBuild:Compile
diff --git a/src/Shared/HandyControl_Shared/Themes/Styles/Base/ColorPickerBaseStyle.xaml b/src/Shared/HandyControl_Shared/Themes/Styles/Base/ColorPickerBaseStyle.xaml
new file mode 100644
index 00000000..62f6a76b
--- /dev/null
+++ b/src/Shared/HandyControl_Shared/Themes/Styles/Base/ColorPickerBaseStyle.xaml
@@ -0,0 +1,245 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Shared/HandyControl_Shared/Themes/Styles/Base/SliderBaseStyle.xaml b/src/Shared/HandyControl_Shared/Themes/Styles/Base/SliderBaseStyle.xaml
index 0fc570c5..aac15bce 100644
--- a/src/Shared/HandyControl_Shared/Themes/Styles/Base/SliderBaseStyle.xaml
+++ b/src/Shared/HandyControl_Shared/Themes/Styles/Base/SliderBaseStyle.xaml
@@ -9,6 +9,7 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Shared/HandyControl_Shared/Themes/Styles/ColorPicker.xaml b/src/Shared/HandyControl_Shared/Themes/Styles/ColorPicker.xaml
index 2adc223b..cd591fc8 100644
--- a/src/Shared/HandyControl_Shared/Themes/Styles/ColorPicker.xaml
+++ b/src/Shared/HandyControl_Shared/Themes/Styles/ColorPicker.xaml
@@ -1,126 +1,10 @@
+ xmlns:controls="clr-namespace:HandyControl.Controls">
-
-
-
-
-
+
-
+
\ No newline at end of file
diff --git a/src/Shared/HandyControl_Shared/Themes/Styles/Slider.xaml b/src/Shared/HandyControl_Shared/Themes/Styles/Slider.xaml
index f5e30b0a..279a3177 100644
--- a/src/Shared/HandyControl_Shared/Themes/Styles/Slider.xaml
+++ b/src/Shared/HandyControl_Shared/Themes/Styles/Slider.xaml
@@ -1,5 +1,4 @@
@@ -10,126 +9,8 @@
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/src/Shared/HandyControl_Shared/Tools/Helper/ArithmeticHelper.cs b/src/Shared/HandyControl_Shared/Tools/Helper/ArithmeticHelper.cs
index d6990e2b..6dffd905 100644
--- a/src/Shared/HandyControl_Shared/Tools/Helper/ArithmeticHelper.cs
+++ b/src/Shared/HandyControl_Shared/Tools/Helper/ArithmeticHelper.cs
@@ -36,9 +36,9 @@ namespace HandyControl.Tools
///
/// 计算控件在窗口中的可见坐标
///
- public static Point CalSafePoint(FrameworkElement element, FrameworkElement showElement, Thickness thickness = default(Thickness))
+ public static Point CalSafePoint(FrameworkElement element, FrameworkElement showElement, Thickness thickness = default)
{
- if (element == null || showElement == null) return default(Point);
+ if (element == null || showElement == null) return default;
var point = element.PointToScreen(new Point(0, 0));
if (point.X < 0) point.X = 0;
@@ -122,19 +122,6 @@ namespace HandyControl.Tools
///
public static double CalAngle(Point center, Point p) => Math.Atan2(p.Y - center.Y, p.X - center.X) * 180 / Math.PI;
- ///
- /// 判断是否是有效的双精度浮点数
- ///
- ///
- ///
- public static bool IsValidDoubleValue(object value)
- {
- var d = (double)value;
- if (!double.IsNaN(d))
- return !double.IsInfinity(d);
- return false;
- }
-
///
/// 计算法线
///
diff --git a/src/Shared/HandyControl_Shared/Tools/Helper/ValidateHelper.cs b/src/Shared/HandyControl_Shared/Tools/Helper/ValidateHelper.cs
index ff69c094..b5c7a21a 100644
--- a/src/Shared/HandyControl_Shared/Tools/Helper/ValidateHelper.cs
+++ b/src/Shared/HandyControl_Shared/Tools/Helper/ValidateHelper.cs
@@ -20,24 +20,88 @@
/// 是否在正浮点数范围内
///
///
- ///
///
- public static bool IsInRangeOfPosDouble(object value, bool includeZero = false)
+ public static bool IsInRangeOfPosDouble(object value)
{
var v = (double)value;
- return !(double.IsNaN(v) || double.IsInfinity(v)) && (includeZero ? v >= 0 : v > 0);
+ return !(double.IsNaN(v) || double.IsInfinity(v)) && v > 0;
+ }
+
+ ///
+ /// 是否在正浮点数范围内(包括0)
+ ///
+ ///
+ ///
+ public static bool IsInRangeOfPosDoubleIncludeZero(object value)
+ {
+ var v = (double)value;
+ return !(double.IsNaN(v) || double.IsInfinity(v)) && v >= 0;
}
///
/// 是否在负浮点数范围内
///
///
- ///
///
- public static bool IsInRangeOfNegDouble(object value, bool includeZero = false)
+ public static bool IsInRangeOfNegDouble(object value)
{
var v = (double)value;
- return !(double.IsNaN(v) || double.IsInfinity(v)) && (includeZero ? v <= 0 : v < 0);
+ return !(double.IsNaN(v) || double.IsInfinity(v)) && v < 0;
+ }
+
+ ///
+ /// 是否在负浮点数范围内(包括0)
+ ///
+ ///
+ ///
+ public static bool IsInRangeOfNegDoubleIncludeZero(object value)
+ {
+ var v = (double)value;
+ return !(double.IsNaN(v) || double.IsInfinity(v)) && v <= 0;
+ }
+
+ ///
+ /// 是否在正整数范围内
+ ///
+ ///
+ ///
+ public static bool IsInRangeOfPosInt(object value)
+ {
+ var v = (int)value;
+ return v > 0;
+ }
+
+ ///
+ /// 是否在正整数范围内(包括0)
+ ///
+ ///
+ ///
+ public static bool IsInRangeOfPosIntIncludeZero(object value)
+ {
+ var v = (int)value;
+ return v >= 0;
+ }
+
+ ///
+ /// 是否在负整数范围内
+ ///
+ ///
+ ///
+ public static bool IsInRangeOfNegInt(object value)
+ {
+ var v = (int)value;
+ return v < 0;
+ }
+
+ ///
+ /// 是否在负整数范围内(包括0)
+ ///
+ ///
+ ///
+ public static bool IsInRangeOfNegIntIncludeZero(object value)
+ {
+ var v = (int)value;
+ return v <= 0;
}
}
}
\ No newline at end of file
diff --git a/src/Shared/HandyControl_Shared/Tools/Helper/VisualHelper.cs b/src/Shared/HandyControl_Shared/Tools/Helper/VisualHelper.cs
index 5ba5ae07..363478e0 100644
--- a/src/Shared/HandyControl_Shared/Tools/Helper/VisualHelper.cs
+++ b/src/Shared/HandyControl_Shared/Tools/Helper/VisualHelper.cs
@@ -42,7 +42,7 @@ namespace HandyControl.Tools
if (result != null) return result;
}
- return default(T);
+ return default;
}
///