chore: use file-scoped namespace
This commit is contained in:
1 parent
99d2fafb72
commit
bbf1b7d4c6
748 files changed
+57929
-58678
No files matched your search
@@ -1,26 +1,25 @@
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
namespace HandyControl.Controls;
|
||||
|
||||
public class CompareSlider : Slider
|
||||
{
|
||||
public class CompareSlider : Slider
|
||||
public static readonly DependencyProperty TargetContentProperty = DependencyProperty.Register(
|
||||
"TargetContent", typeof(object), typeof(CompareSlider), new PropertyMetadata(default(object)));
|
||||
|
||||
public static readonly DependencyProperty SourceContentProperty = DependencyProperty.Register(
|
||||
"SourceContent", typeof(object), typeof(CompareSlider), new PropertyMetadata(default(object)));
|
||||
|
||||
public object TargetContent
|
||||
{
|
||||
public static readonly DependencyProperty TargetContentProperty = DependencyProperty.Register(
|
||||
"TargetContent", typeof(object), typeof(CompareSlider), new PropertyMetadata(default(object)));
|
||||
|
||||
public static readonly DependencyProperty SourceContentProperty = DependencyProperty.Register(
|
||||
"SourceContent", typeof(object), typeof(CompareSlider), new PropertyMetadata(default(object)));
|
||||
|
||||
public object TargetContent
|
||||
{
|
||||
get => GetValue(TargetContentProperty);
|
||||
set => SetValue(TargetContentProperty, value);
|
||||
}
|
||||
|
||||
public object SourceContent
|
||||
{
|
||||
get => GetValue(SourceContentProperty);
|
||||
set => SetValue(SourceContentProperty, value);
|
||||
}
|
||||
get => GetValue(TargetContentProperty);
|
||||
set => SetValue(TargetContentProperty, value);
|
||||
}
|
||||
}
|
||||
|
||||
public object SourceContent
|
||||
{
|
||||
get => GetValue(SourceContentProperty);
|
||||
set => SetValue(SourceContentProperty, value);
|
||||
}
|
||||
}
|
||||
@@ -3,115 +3,114 @@ using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Controls.Primitives;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
namespace HandyControl.Controls;
|
||||
|
||||
public class CompareTrack : Track
|
||||
{
|
||||
public class CompareTrack : Track
|
||||
protected override Size ArrangeOverride(Size arrangeSize)
|
||||
{
|
||||
protected override Size ArrangeOverride(Size arrangeSize)
|
||||
base.ArrangeOverride(arrangeSize);
|
||||
|
||||
var isVertical = Orientation == Orientation.Vertical;
|
||||
ComputeSliderLengths(arrangeSize, isVertical, out var decreaseButtonLength, out var thumbLength,
|
||||
out var increaseButtonLength);
|
||||
|
||||
var offset = new Point();
|
||||
var pieceSize = arrangeSize;
|
||||
var isDirectionReversed = IsDirectionReversed;
|
||||
|
||||
if (isVertical)
|
||||
{
|
||||
base.ArrangeOverride(arrangeSize);
|
||||
CoerceLength(ref decreaseButtonLength, arrangeSize.Height);
|
||||
CoerceLength(ref increaseButtonLength, arrangeSize.Height);
|
||||
CoerceLength(ref thumbLength, arrangeSize.Height);
|
||||
|
||||
var isVertical = Orientation == Orientation.Vertical;
|
||||
ComputeSliderLengths(arrangeSize, isVertical, out var decreaseButtonLength, out var thumbLength,
|
||||
out var increaseButtonLength);
|
||||
offset.Y = isDirectionReversed ? decreaseButtonLength + thumbLength : 0.0;
|
||||
pieceSize.Height = increaseButtonLength;
|
||||
|
||||
var offset = new Point();
|
||||
var pieceSize = arrangeSize;
|
||||
var isDirectionReversed = IsDirectionReversed;
|
||||
IncreaseRepeatButton?.Arrange(new Rect(offset, pieceSize));
|
||||
|
||||
if (isVertical)
|
||||
offset.Y = isDirectionReversed ? 0.0 : increaseButtonLength + thumbLength;
|
||||
pieceSize.Height = decreaseButtonLength;
|
||||
|
||||
if (DecreaseRepeatButton != null)
|
||||
{
|
||||
CoerceLength(ref decreaseButtonLength, arrangeSize.Height);
|
||||
CoerceLength(ref increaseButtonLength, arrangeSize.Height);
|
||||
CoerceLength(ref thumbLength, arrangeSize.Height);
|
||||
|
||||
offset.Y = isDirectionReversed ? decreaseButtonLength + thumbLength : 0.0;
|
||||
pieceSize.Height = increaseButtonLength;
|
||||
|
||||
IncreaseRepeatButton?.Arrange(new Rect(offset, pieceSize));
|
||||
|
||||
offset.Y = isDirectionReversed ? 0.0 : increaseButtonLength + thumbLength;
|
||||
pieceSize.Height = decreaseButtonLength;
|
||||
|
||||
if (DecreaseRepeatButton != null)
|
||||
{
|
||||
DecreaseRepeatButton.Arrange(new Rect(offset, pieceSize));
|
||||
DecreaseRepeatButton.Height = pieceSize.Height;
|
||||
}
|
||||
|
||||
offset.Y = isDirectionReversed ? decreaseButtonLength : increaseButtonLength;
|
||||
pieceSize.Height = thumbLength;
|
||||
|
||||
Thumb?.Arrange(new Rect(offset, pieceSize));
|
||||
}
|
||||
else
|
||||
{
|
||||
CoerceLength(ref decreaseButtonLength, arrangeSize.Width);
|
||||
CoerceLength(ref increaseButtonLength, arrangeSize.Width);
|
||||
CoerceLength(ref thumbLength, arrangeSize.Width);
|
||||
|
||||
offset.X = isDirectionReversed ? increaseButtonLength + thumbLength : 0.0;
|
||||
pieceSize.Width = decreaseButtonLength;
|
||||
|
||||
DecreaseRepeatButton?.Arrange(new Rect(offset, pieceSize));
|
||||
|
||||
|
||||
offset.X = isDirectionReversed ? 0.0 : decreaseButtonLength + thumbLength;
|
||||
pieceSize.Width = increaseButtonLength;
|
||||
|
||||
if (IncreaseRepeatButton != null)
|
||||
{
|
||||
IncreaseRepeatButton.Arrange(new Rect(offset, pieceSize));
|
||||
IncreaseRepeatButton.Width = pieceSize.Width;
|
||||
}
|
||||
|
||||
offset.X = isDirectionReversed ? increaseButtonLength : decreaseButtonLength;
|
||||
pieceSize.Width = thumbLength;
|
||||
|
||||
Thumb?.Arrange(new Rect(offset, pieceSize));
|
||||
DecreaseRepeatButton.Arrange(new Rect(offset, pieceSize));
|
||||
DecreaseRepeatButton.Height = pieceSize.Height;
|
||||
}
|
||||
|
||||
return arrangeSize;
|
||||
offset.Y = isDirectionReversed ? decreaseButtonLength : increaseButtonLength;
|
||||
pieceSize.Height = thumbLength;
|
||||
|
||||
Thumb?.Arrange(new Rect(offset, pieceSize));
|
||||
}
|
||||
else
|
||||
{
|
||||
CoerceLength(ref decreaseButtonLength, arrangeSize.Width);
|
||||
CoerceLength(ref increaseButtonLength, arrangeSize.Width);
|
||||
CoerceLength(ref thumbLength, arrangeSize.Width);
|
||||
|
||||
offset.X = isDirectionReversed ? increaseButtonLength + thumbLength : 0.0;
|
||||
pieceSize.Width = decreaseButtonLength;
|
||||
|
||||
DecreaseRepeatButton?.Arrange(new Rect(offset, pieceSize));
|
||||
|
||||
|
||||
offset.X = isDirectionReversed ? 0.0 : decreaseButtonLength + thumbLength;
|
||||
pieceSize.Width = increaseButtonLength;
|
||||
|
||||
if (IncreaseRepeatButton != null)
|
||||
{
|
||||
IncreaseRepeatButton.Arrange(new Rect(offset, pieceSize));
|
||||
IncreaseRepeatButton.Width = pieceSize.Width;
|
||||
}
|
||||
|
||||
offset.X = isDirectionReversed ? increaseButtonLength : decreaseButtonLength;
|
||||
pieceSize.Width = thumbLength;
|
||||
|
||||
Thumb?.Arrange(new Rect(offset, pieceSize));
|
||||
}
|
||||
|
||||
private void ComputeSliderLengths(Size arrangeSize, bool isVertical, out double decreaseButtonLength,
|
||||
out double thumbLength, out double increaseButtonLength)
|
||||
{
|
||||
var min = Minimum;
|
||||
var range = Math.Max(0.0, Maximum - min);
|
||||
var offset = Math.Min(range, Value - min);
|
||||
|
||||
double trackLength;
|
||||
|
||||
// Compute thumb size
|
||||
if (isVertical)
|
||||
{
|
||||
trackLength = arrangeSize.Height;
|
||||
thumbLength = Thumb?.DesiredSize.Height ?? 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
trackLength = arrangeSize.Width;
|
||||
thumbLength = Thumb?.DesiredSize.Width ?? 0;
|
||||
}
|
||||
|
||||
CoerceLength(ref thumbLength, trackLength);
|
||||
|
||||
var remainingTrackLength = trackLength - thumbLength;
|
||||
|
||||
decreaseButtonLength = remainingTrackLength * offset / range;
|
||||
CoerceLength(ref decreaseButtonLength, remainingTrackLength);
|
||||
|
||||
increaseButtonLength = remainingTrackLength - decreaseButtonLength;
|
||||
CoerceLength(ref increaseButtonLength, remainingTrackLength);
|
||||
}
|
||||
|
||||
private static void CoerceLength(ref double componentLength, double trackLength)
|
||||
{
|
||||
if (componentLength < 0)
|
||||
componentLength = 0.0;
|
||||
else if (componentLength > trackLength || double.IsNaN(componentLength))
|
||||
componentLength = trackLength;
|
||||
}
|
||||
return arrangeSize;
|
||||
}
|
||||
}
|
||||
|
||||
private void ComputeSliderLengths(Size arrangeSize, bool isVertical, out double decreaseButtonLength,
|
||||
out double thumbLength, out double increaseButtonLength)
|
||||
{
|
||||
var min = Minimum;
|
||||
var range = Math.Max(0.0, Maximum - min);
|
||||
var offset = Math.Min(range, Value - min);
|
||||
|
||||
double trackLength;
|
||||
|
||||
// Compute thumb size
|
||||
if (isVertical)
|
||||
{
|
||||
trackLength = arrangeSize.Height;
|
||||
thumbLength = Thumb?.DesiredSize.Height ?? 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
trackLength = arrangeSize.Width;
|
||||
thumbLength = Thumb?.DesiredSize.Width ?? 0;
|
||||
}
|
||||
|
||||
CoerceLength(ref thumbLength, trackLength);
|
||||
|
||||
var remainingTrackLength = trackLength - thumbLength;
|
||||
|
||||
decreaseButtonLength = remainingTrackLength * offset / range;
|
||||
CoerceLength(ref decreaseButtonLength, remainingTrackLength);
|
||||
|
||||
increaseButtonLength = remainingTrackLength - decreaseButtonLength;
|
||||
CoerceLength(ref increaseButtonLength, remainingTrackLength);
|
||||
}
|
||||
|
||||
private static void CoerceLength(ref double componentLength, double trackLength)
|
||||
{
|
||||
if (componentLength < 0)
|
||||
componentLength = 0.0;
|
||||
else if (componentLength > trackLength || double.IsNaN(componentLength))
|
||||
componentLength = trackLength;
|
||||
}
|
||||
}
|
||||
@@ -9,196 +9,195 @@ using System.Windows.Media;
|
||||
using HandyControl.Data;
|
||||
using HandyControl.Interactivity;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
namespace HandyControl.Controls;
|
||||
|
||||
[TemplatePart(Name = TrackKey, Type = typeof(Track))]
|
||||
[TemplatePart(Name = ThumbKey, Type = typeof(FrameworkElement))]
|
||||
public class PreviewSlider : Slider
|
||||
{
|
||||
[TemplatePart(Name = TrackKey, Type = typeof(Track))]
|
||||
[TemplatePart(Name = ThumbKey, Type = typeof(FrameworkElement))]
|
||||
public class PreviewSlider : Slider
|
||||
private AdornerContainer _adorner;
|
||||
|
||||
private const string TrackKey = "PART_Track";
|
||||
|
||||
private const string ThumbKey = "PART_Thumb";
|
||||
|
||||
private FrameworkElement _previewContent;
|
||||
|
||||
private FrameworkElement _thumb;
|
||||
|
||||
private TranslateTransform _transform;
|
||||
|
||||
private Track _track;
|
||||
|
||||
/// <summary>
|
||||
/// 预览内容
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty PreviewContentProperty = DependencyProperty.Register(
|
||||
"PreviewContent", typeof(object), typeof(PreviewSlider), new PropertyMetadata(default(object)));
|
||||
|
||||
/// <summary>
|
||||
/// 预览内容
|
||||
/// </summary>
|
||||
public object PreviewContent
|
||||
{
|
||||
private AdornerContainer _adorner;
|
||||
get => GetValue(PreviewContentProperty);
|
||||
set => SetValue(PreviewContentProperty, value);
|
||||
}
|
||||
|
||||
private const string TrackKey = "PART_Track";
|
||||
public static readonly DependencyProperty PreviewContentOffsetProperty = DependencyProperty.Register(
|
||||
"PreviewContentOffset", typeof(double), typeof(PreviewSlider), new PropertyMetadata(9.0));
|
||||
|
||||
private const string ThumbKey = "PART_Thumb";
|
||||
public double PreviewContentOffset
|
||||
{
|
||||
get => (double) GetValue(PreviewContentOffsetProperty);
|
||||
set => SetValue(PreviewContentOffsetProperty, value);
|
||||
}
|
||||
|
||||
private FrameworkElement _previewContent;
|
||||
public static readonly DependencyProperty PreviewPositionProperty = DependencyProperty.RegisterAttached(
|
||||
"PreviewPosition", typeof(double), typeof(PreviewSlider), new FrameworkPropertyMetadata(ValueBoxes.Double0Box, FrameworkPropertyMetadataOptions.Inherits));
|
||||
|
||||
private FrameworkElement _thumb;
|
||||
public static void SetPreviewPosition(DependencyObject element, double value)
|
||||
=> element.SetValue(PreviewPositionProperty, value);
|
||||
|
||||
private TranslateTransform _transform;
|
||||
public static double GetPreviewPosition(DependencyObject element)
|
||||
=> (double) element.GetValue(PreviewPositionProperty);
|
||||
|
||||
private Track _track;
|
||||
public double PreviewPosition
|
||||
{
|
||||
get => GetPreviewPosition(_previewContent);
|
||||
set => SetPreviewPosition(_previewContent, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 预览内容
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty PreviewContentProperty = DependencyProperty.Register(
|
||||
"PreviewContent", typeof(object), typeof(PreviewSlider), new PropertyMetadata(default(object)));
|
||||
/// <summary>
|
||||
/// 值改变事件
|
||||
/// </summary>
|
||||
public static readonly RoutedEvent PreviewPositionChangedEvent =
|
||||
EventManager.RegisterRoutedEvent("PreviewPositionChanged", RoutingStrategy.Bubble,
|
||||
typeof(EventHandler<FunctionEventArgs<double>>), typeof(PreviewSlider));
|
||||
|
||||
/// <summary>
|
||||
/// 预览内容
|
||||
/// </summary>
|
||||
public object PreviewContent
|
||||
/// <summary>
|
||||
/// 值改变事件
|
||||
/// </summary>
|
||||
public event EventHandler<FunctionEventArgs<double>> PreviewPositionChanged
|
||||
{
|
||||
add => AddHandler(PreviewPositionChangedEvent, value);
|
||||
remove => RemoveHandler(PreviewPositionChangedEvent, value);
|
||||
}
|
||||
|
||||
protected override void OnMouseMove(MouseEventArgs e)
|
||||
{
|
||||
base.OnMouseMove(e);
|
||||
|
||||
if (_previewContent == null) return;
|
||||
|
||||
var p = e.GetPosition(_adorner);
|
||||
var maximum = Maximum;
|
||||
var minimum = Minimum;
|
||||
|
||||
if (Orientation == Orientation.Horizontal)
|
||||
{
|
||||
get => GetValue(PreviewContentProperty);
|
||||
set => SetValue(PreviewContentProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty PreviewContentOffsetProperty = DependencyProperty.Register(
|
||||
"PreviewContentOffset", typeof(double), typeof(PreviewSlider), new PropertyMetadata(9.0));
|
||||
|
||||
public double PreviewContentOffset
|
||||
{
|
||||
get => (double) GetValue(PreviewContentOffsetProperty);
|
||||
set => SetValue(PreviewContentOffsetProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty PreviewPositionProperty = DependencyProperty.RegisterAttached(
|
||||
"PreviewPosition", typeof(double), typeof(PreviewSlider), new FrameworkPropertyMetadata(ValueBoxes.Double0Box, FrameworkPropertyMetadataOptions.Inherits));
|
||||
|
||||
public static void SetPreviewPosition(DependencyObject element, double value)
|
||||
=> element.SetValue(PreviewPositionProperty, value);
|
||||
|
||||
public static double GetPreviewPosition(DependencyObject element)
|
||||
=> (double) element.GetValue(PreviewPositionProperty);
|
||||
|
||||
public double PreviewPosition
|
||||
{
|
||||
get => GetPreviewPosition(_previewContent);
|
||||
set => SetPreviewPosition(_previewContent, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 值改变事件
|
||||
/// </summary>
|
||||
public static readonly RoutedEvent PreviewPositionChangedEvent =
|
||||
EventManager.RegisterRoutedEvent("PreviewPositionChanged", RoutingStrategy.Bubble,
|
||||
typeof(EventHandler<FunctionEventArgs<double>>), typeof(PreviewSlider));
|
||||
|
||||
/// <summary>
|
||||
/// 值改变事件
|
||||
/// </summary>
|
||||
public event EventHandler<FunctionEventArgs<double>> PreviewPositionChanged
|
||||
{
|
||||
add => AddHandler(PreviewPositionChangedEvent, value);
|
||||
remove => RemoveHandler(PreviewPositionChangedEvent, value);
|
||||
}
|
||||
|
||||
protected override void OnMouseMove(MouseEventArgs e)
|
||||
{
|
||||
base.OnMouseMove(e);
|
||||
|
||||
if (_previewContent == null) return;
|
||||
|
||||
var p = e.GetPosition(_adorner);
|
||||
var maximum = Maximum;
|
||||
var minimum = Minimum;
|
||||
|
||||
if (Orientation == Orientation.Horizontal)
|
||||
var pos = !IsDirectionReversed
|
||||
? (e.GetPosition(this).X - _thumb.ActualWidth * 0.5) / _track.ActualWidth * (maximum - minimum) + minimum
|
||||
: (1 - (e.GetPosition(this).X - _thumb.ActualWidth * 0.5) / _track.ActualWidth) * (maximum - minimum) + minimum;
|
||||
if (pos > maximum || pos < 0)
|
||||
{
|
||||
|
||||
var pos = !IsDirectionReversed
|
||||
? (e.GetPosition(this).X - _thumb.ActualWidth * 0.5) / _track.ActualWidth * (maximum - minimum) + minimum
|
||||
: (1 - (e.GetPosition(this).X - _thumb.ActualWidth * 0.5) / _track.ActualWidth) * (maximum - minimum) + minimum;
|
||||
if (pos > maximum || pos < 0)
|
||||
if (_thumb.IsMouseCaptureWithin)
|
||||
{
|
||||
if (_thumb.IsMouseCaptureWithin)
|
||||
{
|
||||
PreviewPosition = Value;
|
||||
}
|
||||
return;
|
||||
PreviewPosition = Value;
|
||||
}
|
||||
|
||||
_transform.X = p.X - _previewContent.ActualWidth * 0.5;
|
||||
_transform.Y = _thumb.TranslatePoint(new Point(), _adorner).Y - _previewContent.ActualHeight - PreviewContentOffset;
|
||||
|
||||
PreviewPosition = _thumb.IsMouseCaptureWithin ? Value : pos;
|
||||
return;
|
||||
}
|
||||
else
|
||||
|
||||
_transform.X = p.X - _previewContent.ActualWidth * 0.5;
|
||||
_transform.Y = _thumb.TranslatePoint(new Point(), _adorner).Y - _previewContent.ActualHeight - PreviewContentOffset;
|
||||
|
||||
PreviewPosition = _thumb.IsMouseCaptureWithin ? Value : pos;
|
||||
}
|
||||
else
|
||||
{
|
||||
var pos = !IsDirectionReversed
|
||||
? (1 - (e.GetPosition(this).Y - _thumb.ActualHeight * 0.5) / _track.ActualHeight) * (maximum - minimum) + minimum
|
||||
: (e.GetPosition(this).Y - _thumb.ActualHeight * 0.5) / _track.ActualHeight * (maximum - minimum) + minimum;
|
||||
if (pos > maximum || pos < 0)
|
||||
{
|
||||
var pos = !IsDirectionReversed
|
||||
? (1 - (e.GetPosition(this).Y - _thumb.ActualHeight * 0.5) / _track.ActualHeight) * (maximum - minimum) + minimum
|
||||
: (e.GetPosition(this).Y - _thumb.ActualHeight * 0.5) / _track.ActualHeight * (maximum - minimum) + minimum;
|
||||
if (pos > maximum || pos < 0)
|
||||
if (_thumb.IsMouseCaptureWithin)
|
||||
{
|
||||
if (_thumb.IsMouseCaptureWithin)
|
||||
{
|
||||
PreviewPosition = Value;
|
||||
}
|
||||
return;
|
||||
PreviewPosition = Value;
|
||||
}
|
||||
|
||||
_transform.X = _thumb.TranslatePoint(new Point(), _adorner).X - _previewContent.ActualWidth - PreviewContentOffset;
|
||||
_transform.Y = p.Y - _previewContent.ActualHeight * 0.5;
|
||||
|
||||
PreviewPosition = _thumb.IsMouseCaptureWithin ? Value : pos;
|
||||
return;
|
||||
}
|
||||
|
||||
RaiseEvent(new FunctionEventArgs<double>(PreviewPositionChangedEvent, this)
|
||||
{
|
||||
Info = PreviewPosition
|
||||
});
|
||||
_transform.X = _thumb.TranslatePoint(new Point(), _adorner).X - _previewContent.ActualWidth - PreviewContentOffset;
|
||||
_transform.Y = p.Y - _previewContent.ActualHeight * 0.5;
|
||||
|
||||
PreviewPosition = _thumb.IsMouseCaptureWithin ? Value : pos;
|
||||
}
|
||||
|
||||
protected override void OnMouseEnter(MouseEventArgs e)
|
||||
RaiseEvent(new FunctionEventArgs<double>(PreviewPositionChangedEvent, this)
|
||||
{
|
||||
base.OnMouseEnter(e);
|
||||
Info = PreviewPosition
|
||||
});
|
||||
}
|
||||
|
||||
if (_adorner == null)
|
||||
{
|
||||
var layer = AdornerLayer.GetAdornerLayer(this);
|
||||
if (layer == null) return;
|
||||
_adorner = new AdornerContainer(layer)
|
||||
{
|
||||
Child = _previewContent
|
||||
};
|
||||
layer.Add(_adorner);
|
||||
}
|
||||
}
|
||||
protected override void OnMouseEnter(MouseEventArgs e)
|
||||
{
|
||||
base.OnMouseEnter(e);
|
||||
|
||||
protected override void OnMouseLeave(MouseEventArgs e)
|
||||
if (_adorner == null)
|
||||
{
|
||||
base.OnMouseLeave(e);
|
||||
|
||||
var layer = AdornerLayer.GetAdornerLayer(this);
|
||||
if (layer != null)
|
||||
if (layer == null) return;
|
||||
_adorner = new AdornerContainer(layer)
|
||||
{
|
||||
layer.Remove(_adorner);
|
||||
}
|
||||
else if (_adorner is { Parent: AdornerLayer parent })
|
||||
{
|
||||
parent.Remove(_adorner);
|
||||
}
|
||||
|
||||
if (_adorner != null)
|
||||
{
|
||||
_adorner.Child = null;
|
||||
_adorner = null;
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnApplyTemplate()
|
||||
{
|
||||
base.OnApplyTemplate();
|
||||
|
||||
var contentControl = new ContentControl
|
||||
{
|
||||
DataContext = this
|
||||
Child = _previewContent
|
||||
};
|
||||
contentControl.SetBinding(ContentControl.ContentProperty, new Binding(PreviewContentProperty.Name) { Source = this });
|
||||
_previewContent = contentControl;
|
||||
|
||||
_track = Template.FindName(TrackKey, this) as Track;
|
||||
_thumb = Template.FindName(ThumbKey, this) as FrameworkElement;
|
||||
|
||||
if (_previewContent != null)
|
||||
{
|
||||
_transform = new TranslateTransform();
|
||||
|
||||
_previewContent.HorizontalAlignment = HorizontalAlignment.Left;
|
||||
_previewContent.VerticalAlignment = VerticalAlignment.Top;
|
||||
_previewContent.RenderTransform = _transform;
|
||||
}
|
||||
layer.Add(_adorner);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnMouseLeave(MouseEventArgs e)
|
||||
{
|
||||
base.OnMouseLeave(e);
|
||||
|
||||
var layer = AdornerLayer.GetAdornerLayer(this);
|
||||
if (layer != null)
|
||||
{
|
||||
layer.Remove(_adorner);
|
||||
}
|
||||
else if (_adorner is { Parent: AdornerLayer parent })
|
||||
{
|
||||
parent.Remove(_adorner);
|
||||
}
|
||||
|
||||
if (_adorner != null)
|
||||
{
|
||||
_adorner.Child = null;
|
||||
_adorner = null;
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnApplyTemplate()
|
||||
{
|
||||
base.OnApplyTemplate();
|
||||
|
||||
var contentControl = new ContentControl
|
||||
{
|
||||
DataContext = this
|
||||
};
|
||||
contentControl.SetBinding(ContentControl.ContentProperty, new Binding(PreviewContentProperty.Name) { Source = this });
|
||||
_previewContent = contentControl;
|
||||
|
||||
_track = Template.FindName(TrackKey, this) as Track;
|
||||
_thumb = Template.FindName(ThumbKey, this) as FrameworkElement;
|
||||
|
||||
if (_previewContent != null)
|
||||
{
|
||||
_transform = new TranslateTransform();
|
||||
|
||||
_previewContent.HorizontalAlignment = HorizontalAlignment.Left;
|
||||
_previewContent.VerticalAlignment = VerticalAlignment.Top;
|
||||
_previewContent.RenderTransform = _transform;
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -3,44 +3,43 @@ using System.Windows;
|
||||
using System.Windows.Controls.Primitives;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
namespace HandyControl.Controls;
|
||||
|
||||
public class RangeThumb : Thumb
|
||||
{
|
||||
public class RangeThumb : Thumb
|
||||
public static readonly DependencyProperty ContentProperty = DependencyProperty.Register(
|
||||
"Content", typeof(object), typeof(RangeThumb), new PropertyMetadata(default(object)));
|
||||
|
||||
public object Content
|
||||
{
|
||||
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
|
||||
});
|
||||
}
|
||||
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
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -8,452 +8,451 @@ using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using HandyControl.Data;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
namespace HandyControl.Controls;
|
||||
|
||||
public class RangeTrack : FrameworkElement
|
||||
{
|
||||
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;
|
||||
|
||||
public RepeatButton DecreaseRepeatButton
|
||||
{
|
||||
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;
|
||||
|
||||
public RepeatButton DecreaseRepeatButton
|
||||
get => _decreaseButton;
|
||||
set
|
||||
{
|
||||
get => _decreaseButton;
|
||||
set
|
||||
if (Equals(_increaseButton, value) || Equals(_centerButton, value))
|
||||
{
|
||||
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
|
||||
}
|
||||
throw new NotSupportedException("SameButtons");
|
||||
}
|
||||
}
|
||||
UpdateComponent(_decreaseButton, value);
|
||||
_decreaseButton = value;
|
||||
|
||||
public RepeatButton CenterRepeatButton
|
||||
{
|
||||
get => _centerButton;
|
||||
set
|
||||
if (_decreaseButton != null)
|
||||
{
|
||||
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, ValueBoxes.BooleanBox(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;
|
||||
|
||||
ArrangeThumb(isDirectionReversed, false, offset, pieceSize);
|
||||
|
||||
offset.Y = isDirectionReversed ? decreaseButtonLength : increaseButtonLength;
|
||||
pieceSize.Height = thumbEndLength;
|
||||
|
||||
ArrangeThumb(isDirectionReversed, true, 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;
|
||||
|
||||
ArrangeThumb(isDirectionReversed, false, offset, pieceSize);
|
||||
|
||||
offset.X = isDirectionReversed
|
||||
? increaseButtonLength + thumbStartLength + centerButtonLength
|
||||
: decreaseButtonLength + thumbEndLength + centerButtonLength;
|
||||
pieceSize.Width = thumbEndLength;
|
||||
|
||||
ArrangeThumb(isDirectionReversed, true, offset, pieceSize);
|
||||
}
|
||||
|
||||
return arrangeSize;
|
||||
}
|
||||
|
||||
private void ArrangeThumb(bool isDirectionReversed, bool isStart, Point offset, Size pieceSize)
|
||||
{
|
||||
if (isStart)
|
||||
{
|
||||
if (isDirectionReversed)
|
||||
{
|
||||
ThumbStart?.Arrange(new Rect(offset, pieceSize));
|
||||
}
|
||||
else
|
||||
{
|
||||
ThumbEnd?.Arrange(new Rect(offset, pieceSize));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (isDirectionReversed)
|
||||
{
|
||||
ThumbEnd?.Arrange(new Rect(offset, pieceSize));
|
||||
}
|
||||
else
|
||||
{
|
||||
ThumbStart?.Arrange(new Rect(offset, pieceSize));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 (var 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)
|
||||
{
|
||||
return Orientation == Orientation.Horizontal
|
||||
? !IsDirectionReversed
|
||||
? pt.X / RenderSize.Width * Maximum
|
||||
: (1 - pt.X / RenderSize.Width) * Maximum
|
||||
: !IsDirectionReversed
|
||||
? pt.Y / RenderSize.Height * Maximum
|
||||
: (1 - pt.X / RenderSize.Height) * Maximum;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
_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();
|
||||
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, ValueBoxes.BooleanBox(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;
|
||||
|
||||
ArrangeThumb(isDirectionReversed, false, offset, pieceSize);
|
||||
|
||||
offset.Y = isDirectionReversed ? decreaseButtonLength : increaseButtonLength;
|
||||
pieceSize.Height = thumbEndLength;
|
||||
|
||||
ArrangeThumb(isDirectionReversed, true, 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;
|
||||
|
||||
ArrangeThumb(isDirectionReversed, false, offset, pieceSize);
|
||||
|
||||
offset.X = isDirectionReversed
|
||||
? increaseButtonLength + thumbStartLength + centerButtonLength
|
||||
: decreaseButtonLength + thumbEndLength + centerButtonLength;
|
||||
pieceSize.Width = thumbEndLength;
|
||||
|
||||
ArrangeThumb(isDirectionReversed, true, offset, pieceSize);
|
||||
}
|
||||
|
||||
return arrangeSize;
|
||||
}
|
||||
|
||||
private void ArrangeThumb(bool isDirectionReversed, bool isStart, Point offset, Size pieceSize)
|
||||
{
|
||||
if (isStart)
|
||||
{
|
||||
if (isDirectionReversed)
|
||||
{
|
||||
ThumbStart?.Arrange(new Rect(offset, pieceSize));
|
||||
}
|
||||
else
|
||||
{
|
||||
ThumbEnd?.Arrange(new Rect(offset, pieceSize));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (isDirectionReversed)
|
||||
{
|
||||
ThumbEnd?.Arrange(new Rect(offset, pieceSize));
|
||||
}
|
||||
else
|
||||
{
|
||||
ThumbStart?.Arrange(new Rect(offset, pieceSize));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 (var 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)
|
||||
{
|
||||
return Orientation == Orientation.Horizontal
|
||||
? !IsDirectionReversed
|
||||
? pt.X / RenderSize.Width * Maximum
|
||||
: (1 - pt.X / RenderSize.Width) * Maximum
|
||||
: !IsDirectionReversed
|
||||
? pt.Y / RenderSize.Height * Maximum
|
||||
: (1 - pt.X / RenderSize.Height) * Maximum;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
_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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,170 +5,169 @@ using System.Windows.Controls;
|
||||
using HandyControl.Data;
|
||||
using HandyControl.Tools;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
namespace HandyControl.Controls;
|
||||
|
||||
public class TwoWayRangeBase : Control
|
||||
{
|
||||
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)
|
||||
{
|
||||
public static readonly DependencyProperty MinimumProperty = DependencyProperty.Register(
|
||||
"Minimum", typeof(double), typeof(TwoWayRangeBase),
|
||||
new PropertyMetadata(ValueBoxes.Double0Box, OnMinimumChanged), ValidateHelper.IsInRangeOfDouble);
|
||||
var ctrl = (TwoWayRangeBase) d;
|
||||
|
||||
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 DoubleRange
|
||||
{
|
||||
Start = (double) e.OldValue,
|
||||
End = ctrl.ValueEnd
|
||||
}, new DoubleRange
|
||||
{
|
||||
Start = (double) e.NewValue,
|
||||
End = ctrl.ValueEnd
|
||||
});
|
||||
}
|
||||
|
||||
protected virtual void OnValueChanged(DoubleRange oldValue, DoubleRange newValue) => RaiseEvent(
|
||||
new RoutedPropertyChangedEventArgs<DoubleRange>(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 DoubleRange
|
||||
{
|
||||
Start = ctrl.ValueStart,
|
||||
End = (double) e.OldValue
|
||||
}, new DoubleRange
|
||||
{
|
||||
Start = ctrl.ValueStart,
|
||||
End = (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<DoubleRange>), typeof(TwoWayRangeBase));
|
||||
|
||||
public event RoutedPropertyChangedEventHandler<DoubleRange> ValueChanged
|
||||
{
|
||||
add => AddHandler(ValueChangedEvent, value);
|
||||
remove => RemoveHandler(ValueChangedEvent, value);
|
||||
}
|
||||
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 DoubleRange
|
||||
{
|
||||
Start = (double) e.OldValue,
|
||||
End = ctrl.ValueEnd
|
||||
}, new DoubleRange
|
||||
{
|
||||
Start = (double) e.NewValue,
|
||||
End = ctrl.ValueEnd
|
||||
});
|
||||
}
|
||||
|
||||
protected virtual void OnValueChanged(DoubleRange oldValue, DoubleRange newValue) => RaiseEvent(
|
||||
new RoutedPropertyChangedEventArgs<DoubleRange>(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 DoubleRange
|
||||
{
|
||||
Start = ctrl.ValueStart,
|
||||
End = (double) e.OldValue
|
||||
}, new DoubleRange
|
||||
{
|
||||
Start = ctrl.ValueStart,
|
||||
End = (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<DoubleRange>), typeof(TwoWayRangeBase));
|
||||
|
||||
public event RoutedPropertyChangedEventHandler<DoubleRange> ValueChanged
|
||||
{
|
||||
add => AddHandler(ValueChangedEvent, value);
|
||||
remove => RemoveHandler(ValueChangedEvent, value);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user