using System; using System.Windows; using System.Windows.Controls; using System.Windows.Controls.Primitives; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using HandyControl.Data; using HandyControl.Interactivity; namespace HandyControl.Controls; [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; /// /// 预览内容 /// public static readonly DependencyProperty PreviewContentProperty = DependencyProperty.Register( nameof(PreviewContent), typeof(object), typeof(PreviewSlider), new PropertyMetadata(default(object))); /// /// 预览内容 /// public object PreviewContent { get => GetValue(PreviewContentProperty); set => SetValue(PreviewContentProperty, value); } public static readonly DependencyProperty PreviewContentOffsetProperty = DependencyProperty.Register( nameof(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); } /// /// 值改变事件 /// public static readonly RoutedEvent PreviewPositionChangedEvent = EventManager.RegisterRoutedEvent("PreviewPositionChanged", RoutingStrategy.Bubble, typeof(EventHandler>), typeof(PreviewSlider)); /// /// 值改变事件 /// public event EventHandler> 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) { if (_thumb.IsMouseCaptureWithin) { PreviewPosition = Value; } return; } _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) { if (_thumb.IsMouseCaptureWithin) { PreviewPosition = Value; } return; } _transform.X = _thumb.TranslatePoint(new Point(), _adorner).X - _previewContent.ActualWidth - PreviewContentOffset; _transform.Y = p.Y - _previewContent.ActualHeight * 0.5; PreviewPosition = _thumb.IsMouseCaptureWithin ? Value : pos; } RaiseEvent(new FunctionEventArgs(PreviewPositionChangedEvent, this) { Info = PreviewPosition }); } protected override void OnMouseEnter(MouseEventArgs e) { base.OnMouseEnter(e); if (_adorner == null) { var layer = AdornerLayer.GetAdornerLayer(this); if (layer == null) return; _adorner = new AdornerContainer(layer) { Child = _previewContent }; 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; } } }