diff --git a/EleCho.WpfSuite/Controls/ListBox.cs b/EleCho.WpfSuite/Controls/ListBox.cs index 8f5363821..633d01a12 100644 --- a/EleCho.WpfSuite/Controls/ListBox.cs +++ b/EleCho.WpfSuite/Controls/ListBox.cs @@ -14,59 +14,56 @@ using System.Windows.Shapes; namespace EleCho.WpfSuite { - /// - public class ListBox : System.Windows.Controls.ListBox - { - static ListBox() - { - DefaultStyleKeyProperty.OverrideMetadata(typeof(ListBox), new FrameworkPropertyMetadata(typeof(ListBox))); - } + /// + public class ListBox : System.Windows.Controls.ListBox + { + static ListBox() + { + DefaultStyleKeyProperty.OverrideMetadata(typeof(ListBox), new FrameworkPropertyMetadata(typeof(ListBox))); + } - /// - /// The CornerRadius property allows users to control the roundness of the corners independently by - /// setting a radius value for each corner. Radius values that are too large are scaled so that they - /// smoothly blend from corner to corner. - /// - public CornerRadius CornerRadius - { - get { return (CornerRadius)GetValue(CornerRadiusProperty); } - set { SetValue(CornerRadiusProperty, value); } - } + /// + /// The CornerRadius property allows users to control the roundness of the corners independently by + /// setting a radius value for each corner. Radius values that are too large are scaled so that they + /// smoothly blend from corner to corner. + /// + public CornerRadius CornerRadius { + get { return (CornerRadius)GetValue(CornerRadiusProperty); } + set { SetValue(CornerRadiusProperty, value); } + } - /// - /// Background when disabled - /// - public Brush DisabledBackground - { - get { return (Brush)GetValue(DisabledBackgroundProperty); } - set { SetValue(DisabledBackgroundProperty, value); } - } + /// + /// Background when disabled + /// + public Brush DisabledBackground { + get { return (Brush)GetValue(DisabledBackgroundProperty); } + set { SetValue(DisabledBackgroundProperty, value); } + } - /// - /// BorderBrush when pressed by mouse - /// - public Brush DisabledBorderBrush - { - get { return (Brush)GetValue(DisabledBorderBrushProperty); } - set { SetValue(DisabledBorderBrushProperty, value); } - } + /// + /// BorderBrush when pressed by mouse + /// + public Brush DisabledBorderBrush { + get { return (Brush)GetValue(DisabledBorderBrushProperty); } + set { SetValue(DisabledBorderBrushProperty, value); } + } - /// - /// DependencyProperty of property - /// - public static readonly DependencyProperty CornerRadiusProperty = - System.Windows.Controls.Border.CornerRadiusProperty.AddOwner(typeof(ListBox)); + /// + /// DependencyProperty of property + /// + public static readonly DependencyProperty CornerRadiusProperty = + System.Windows.Controls.Border.CornerRadiusProperty.AddOwner(typeof(ListBox)); - /// - /// The DependencyProperty of property - /// - public static readonly DependencyProperty DisabledBackgroundProperty = - DependencyProperty.Register(nameof(DisabledBackground), typeof(Brush), typeof(ListBox), new FrameworkPropertyMetadata(null)); + /// + /// The DependencyProperty of property + /// + public static readonly DependencyProperty DisabledBackgroundProperty = + DependencyProperty.Register(nameof(DisabledBackground), typeof(Brush), typeof(ListBox), new FrameworkPropertyMetadata(null)); - /// - /// The DependencyProperty of property - /// - public static readonly DependencyProperty DisabledBorderBrushProperty = - DependencyProperty.Register(nameof(DisabledBorderBrush), typeof(Brush), typeof(ListBox), new FrameworkPropertyMetadata(null)); - } + /// + /// The DependencyProperty of property + /// + public static readonly DependencyProperty DisabledBorderBrushProperty = + DependencyProperty.Register(nameof(DisabledBorderBrush), typeof(Brush), typeof(ListBox), new FrameworkPropertyMetadata(null)); + } } diff --git a/EleCho.WpfSuite/Controls/ListBoxResources.xaml b/EleCho.WpfSuite/Controls/ListBoxResources.xaml index b971ec639..980580efb 100644 --- a/EleCho.WpfSuite/Controls/ListBoxResources.xaml +++ b/EleCho.WpfSuite/Controls/ListBoxResources.xaml @@ -23,19 +23,19 @@ + Background="{TemplateBinding Background}" + BorderBrush="{TemplateBinding BorderBrush}" + BorderThickness="{TemplateBinding BorderThickness}" + CornerRadius="{TemplateBinding CornerRadius}" + Padding="1" + SnapsToDevicePixels="true"> - - + + diff --git a/EleCho.WpfSuite/Controls/ListView.cs b/EleCho.WpfSuite/Controls/ListView.cs index f85699cca..cb9756d2d 100644 --- a/EleCho.WpfSuite/Controls/ListView.cs +++ b/EleCho.WpfSuite/Controls/ListView.cs @@ -3,61 +3,58 @@ using System.Windows.Media; namespace EleCho.WpfSuite { - /// - public class ListView : System.Windows.Controls.ListView - { - static ListView() - { - DefaultStyleKeyProperty.OverrideMetadata(typeof(ListView), new FrameworkPropertyMetadata(typeof(ListView))); - } - - - /// - /// The CornerRadius property allows users to control the roundness of the corners independently by - /// setting a radius value for each corner. Radius values that are too large are scaled so that they - /// smoothly blend from corner to corner. - /// - public CornerRadius CornerRadius - { - get { return (CornerRadius)GetValue(CornerRadiusProperty); } - set { SetValue(CornerRadiusProperty, value); } - } - - /// - /// Background when disabled - /// - public Brush DisabledBackground - { - get { return (Brush)GetValue(DisabledBackgroundProperty); } - set { SetValue(DisabledBackgroundProperty, value); } - } - - /// - /// BorderBrush when pressed by mouse - /// - public Brush DisabledBorderBrush - { - get { return (Brush)GetValue(DisabledBorderBrushProperty); } - set { SetValue(DisabledBorderBrushProperty, value); } - } - - - /// - /// DependencyProperty of property - /// - public static readonly DependencyProperty CornerRadiusProperty = + /// + public class ListView : System.Windows.Controls.ListView + { + static ListView() + { + DefaultStyleKeyProperty.OverrideMetadata(typeof(ListView), new FrameworkPropertyMetadata(typeof(ListView))); + } + + + /// + /// The CornerRadius property allows users to control the roundness of the corners independently by + /// setting a radius value for each corner. Radius values that are too large are scaled so that they + /// smoothly blend from corner to corner. + /// + public CornerRadius CornerRadius { + get { return (CornerRadius)GetValue(CornerRadiusProperty); } + set { SetValue(CornerRadiusProperty, value); } + } + + /// + /// Background when disabled + /// + public Brush DisabledBackground { + get { return (Brush)GetValue(DisabledBackgroundProperty); } + set { SetValue(DisabledBackgroundProperty, value); } + } + + /// + /// BorderBrush when pressed by mouse + /// + public Brush DisabledBorderBrush { + get { return (Brush)GetValue(DisabledBorderBrushProperty); } + set { SetValue(DisabledBorderBrushProperty, value); } + } + + + /// + /// DependencyProperty of property + /// + public static readonly DependencyProperty CornerRadiusProperty = System.Windows.Controls.Border.CornerRadiusProperty.AddOwner(typeof(ListView)); - /// - /// The DependencyProperty of property - /// - public static readonly DependencyProperty DisabledBackgroundProperty = - DependencyProperty.Register(nameof(DisabledBackground), typeof(Brush), typeof(ListView), new FrameworkPropertyMetadata(null)); - - /// - /// The DependencyProperty of property - /// - public static readonly DependencyProperty DisabledBorderBrushProperty = - DependencyProperty.Register(nameof(DisabledBorderBrush), typeof(Brush), typeof(ListView), new FrameworkPropertyMetadata(null)); - } + /// + /// The DependencyProperty of property + /// + public static readonly DependencyProperty DisabledBackgroundProperty = + DependencyProperty.Register(nameof(DisabledBackground), typeof(Brush), typeof(ListView), new FrameworkPropertyMetadata(null)); + + /// + /// The DependencyProperty of property + /// + public static readonly DependencyProperty DisabledBorderBrushProperty = + DependencyProperty.Register(nameof(DisabledBorderBrush), typeof(Brush), typeof(ListView), new FrameworkPropertyMetadata(null)); + } } diff --git a/EleCho.WpfSuite/Controls/ListViewResources.xaml b/EleCho.WpfSuite/Controls/ListViewResources.xaml index a13a101f3..b55d9454b 100644 --- a/EleCho.WpfSuite/Controls/ListViewResources.xaml +++ b/EleCho.WpfSuite/Controls/ListViewResources.xaml @@ -23,19 +23,19 @@ + Background="{TemplateBinding Background}" + BorderBrush="{TemplateBinding BorderBrush}" + BorderThickness="{TemplateBinding BorderThickness}" + CornerRadius="{TemplateBinding CornerRadius}" + Padding="1" + SnapsToDevicePixels="true"> - - + + diff --git a/EleCho.WpfSuite/Controls/ScrollViewer.cs b/EleCho.WpfSuite/Controls/ScrollViewer.cs index 82b9d7b1a..ca0c820db 100644 --- a/EleCho.WpfSuite/Controls/ScrollViewer.cs +++ b/EleCho.WpfSuite/Controls/ScrollViewer.cs @@ -20,437 +20,427 @@ using System.Windows.Shapes; namespace EleCho.WpfSuite { - /// - public class ScrollViewer : System.Windows.Controls.ScrollViewer - { - static ScrollViewer() - { - DefaultStyleKeyProperty.OverrideMetadata(typeof(ScrollViewer), new FrameworkPropertyMetadata(typeof(ScrollViewer))); + /// + public class ScrollViewer : System.Windows.Controls.ScrollViewer + { + static ScrollViewer() + { + DefaultStyleKeyProperty.OverrideMetadata(typeof(ScrollViewer), new FrameworkPropertyMetadata(typeof(ScrollViewer))); #if NETCOREAPP - _propertyHandlesMouseWheelScrollingGetter = typeof(ScrollViewer) - .GetProperty("HandlesMouseWheelScrolling", BindingFlags.Instance | BindingFlags.NonPublic)! - .GetGetMethod(true)! - .CreateDelegate(); + _propertyHandlesMouseWheelScrollingGetter = typeof(ScrollViewer) + .GetProperty("HandlesMouseWheelScrolling", BindingFlags.Instance | BindingFlags.NonPublic)! + .GetGetMethod(true)! + .CreateDelegate(); #else - _propertyHandlesMouseWheelScrollingGetter = (GetBool)typeof(ScrollViewer) - .GetProperty("HandlesMouseWheelScrolling", BindingFlags.Instance | BindingFlags.NonPublic)! - .GetGetMethod(true)! - .CreateDelegate(typeof(GetBool)); + _propertyHandlesMouseWheelScrollingGetter = (GetBool)typeof(ScrollViewer) + .GetProperty("HandlesMouseWheelScrolling", BindingFlags.Instance | BindingFlags.NonPublic)! + .GetGetMethod(true)! + .CreateDelegate(typeof(GetBool)); #endif - } - - private delegate bool GetBool(ScrollViewer scrollViewer); - private static readonly GetBool _propertyHandlesMouseWheelScrollingGetter; - private static readonly IEasingFunction _scrollingAnimationEase = new CubicEase(){ EasingMode = EasingMode.EaseOut }; - private const long _millisecondsBetweenTouchpadScrolling = 100; - - private bool _animationRunning = false; - private int _lastScrollDelta = 0; - private int _lastVerticalScrollingDelta = 0; - private int _lastHorizontalScrollingDelta = 0; - private long _lastScrollingTick; - - private FrameworkElement? _scrollContentPresenter; - - /// - public override void OnApplyTemplate() - { - base.OnApplyTemplate(); - - _scrollContentPresenter = GetTemplateChild("PART_ScrollContentPresenter") as FrameworkElement; - } - - private void CoreScrollWithWheelDelta(MouseWheelEventArgs e) - { - if (e.Handled) - { - return; - } - - if (!AlwaysHandleMouseWheelScrolling && - !_propertyHandlesMouseWheelScrollingGetter.Invoke(this)) - { - return; - } - - bool vertical = ExtentHeight > 0; - bool horizontal = ExtentWidth > 0; - - var tickCount = Environment.TickCount; - var isTouchpadScrolling = - e.Delta % Mouse.MouseWheelDeltaForOneLine != 0 || - (tickCount - _lastScrollingTick < _millisecondsBetweenTouchpadScrolling && _lastScrollDelta % Mouse.MouseWheelDeltaForOneLine != 0); - - double scrollDelta = e.Delta; - - if (isTouchpadScrolling) - { - // touchpad 应该滚动更慢一些, 所以这里预先除以一个合适的值 - scrollDelta /= 2; - - // - scrollDelta *= TouchpadScrollDeltaFactor; - } - else - { - scrollDelta *= MouseScrollDeltaFactor; - } - - if (vertical) - { - if (ScrollInfo is IScrollInfo scrollInfo) - { - // 考虑到 VirtualizingPanel 可能是虚拟的大小, 所以这里需要校正 Delta - scrollDelta *= scrollInfo.ViewportHeight / (_scrollContentPresenter?.ActualHeight ?? ActualHeight); - } - - var sameDirectionAsLast = Math.Sign(e.Delta) == Math.Sign(_lastVerticalScrollingDelta); - var nowOffset = sameDirectionAsLast && _animationRunning ? VerticalOffsetTarget : VerticalOffset; - var newOffset = nowOffset - scrollDelta; - - if (newOffset < 0) - newOffset = 0; - if (newOffset > ScrollableHeight) - newOffset = ScrollableHeight; - - SetValue(VerticalOffsetTargetPropertyKey, newOffset); - BeginAnimation(ScrollViewerUtils.VerticalOffsetProperty, null); - - if (!EnableScrollingAnimation || isTouchpadScrolling) - { - ScrollToVerticalOffset(newOffset); - } - else - { - var diff = newOffset - VerticalOffset; - var absDiff = Math.Abs(diff); - var duration = ScrollingAnimationDuration; - if (absDiff < Mouse.MouseWheelDeltaForOneLine) - { - duration = new Duration(TimeSpan.FromTicks((long)(duration.TimeSpan.Ticks * absDiff / Mouse.MouseWheelDeltaForOneLine))); - } - - DoubleAnimation doubleAnimation = new DoubleAnimation() - { - EasingFunction = _scrollingAnimationEase, - Duration = duration, - From = VerticalOffset, - To = newOffset, - }; - - doubleAnimation.Completed += DoubleAnimation_Completed; - - _animationRunning = true; - BeginAnimation(ScrollViewerUtils.VerticalOffsetProperty, doubleAnimation, HandoffBehavior.SnapshotAndReplace); - } - - _lastVerticalScrollingDelta = e.Delta; - } - else if (horizontal) - { - if (ScrollInfo is IScrollInfo scrollInfo) - { - // 考虑到 VirtualizingPanel 可能是虚拟的大小, 所以这里需要校正 Delta - scrollDelta *= scrollInfo.ViewportWidth / (_scrollContentPresenter?.ActualWidth ?? ActualWidth); - } - - var sameDirectionAsLast = Math.Sign(e.Delta) == Math.Sign(_lastHorizontalScrollingDelta); - var nowOffset = sameDirectionAsLast && _animationRunning ? HorizontalOffsetTarget : HorizontalOffset; - var newOffset = nowOffset - scrollDelta; - - if (newOffset < 0) - newOffset = 0; - if (newOffset > ScrollableWidth) - newOffset = ScrollableWidth; - - SetValue(HorizontalOffsetTargetPropertyKey, newOffset); - BeginAnimation(ScrollViewerUtils.HorizontalOffsetProperty, null); - - if (!EnableScrollingAnimation || isTouchpadScrolling) - { - ScrollToHorizontalOffset(newOffset); - } - else - { - var diff = newOffset - HorizontalOffset; - var absDiff = Math.Abs(diff); - var duration = ScrollingAnimationDuration; - if (absDiff < Mouse.MouseWheelDeltaForOneLine) - { - duration = new Duration(TimeSpan.FromTicks((long)(duration.TimeSpan.Ticks * absDiff / Mouse.MouseWheelDeltaForOneLine))); - } - - DoubleAnimation doubleAnimation = new DoubleAnimation() - { - EasingFunction = _scrollingAnimationEase, - Duration = duration, - From = HorizontalOffset, - To = newOffset, - }; - - doubleAnimation.Completed += DoubleAnimation_Completed; - - _animationRunning = true; - BeginAnimation(ScrollViewerUtils.HorizontalOffsetProperty, doubleAnimation, HandoffBehavior.SnapshotAndReplace); - } - - _lastHorizontalScrollingDelta = e.Delta; - } - - _lastScrollingTick = tickCount; - _lastScrollDelta = e.Delta; - - e.Handled = true; - } - - private void DoubleAnimation_Completed(object? sender, EventArgs e) - { - _animationRunning = false; - } - - /// - protected override void OnMouseWheel(MouseWheelEventArgs e) - { - if (!ScrollWithWheelDelta) - { - base.OnMouseWheel(e); - } - else - { - Debug.WriteLine(e.Delta); - - CoreScrollWithWheelDelta(e); - } - } - - /// - /// The horizontal offset of scrolling target - /// - public double HorizontalOffsetTarget - { - get { return (double)GetValue(HorizontalOffsetTargetProperty); } - } - - /// - /// The vertical offset of scrolling target - /// - public double VerticalOffsetTarget - { - get { return (double)GetValue(VerticalOffsetTargetProperty); } - } - - /// - /// Scroll with wheel delta instead of scrolling fixed number of lines - /// - public bool ScrollWithWheelDelta - { - get { return (bool)GetValue(ScrollWithWheelDeltaProperty); } - set { SetValue(ScrollWithWheelDeltaProperty, value); } - } - - /// - /// Enable scrolling animation while using mouse
- /// You need to set ScrollWithWheelDelta to true to use this - ///
- public bool EnableScrollingAnimation - { - get { return (bool)GetValue(EnableScrollingAnimationProperty); } - set { SetValue(EnableScrollingAnimationProperty, value); } - } - - /// - /// Scrolling animation duration - /// - public Duration ScrollingAnimationDuration - { - get { return (Duration)GetValue(ScrollingAnimationDurationProperty); } - set { SetValue(ScrollingAnimationDurationProperty, value); } - } - - /// - /// Delta value factor while mouse scrolling - /// - public double MouseScrollDeltaFactor - { - get { return (double)GetValue(MouseScrollDeltaFactorProperty); } - set { SetValue(MouseScrollDeltaFactorProperty, value); } - } - - /// - /// Delta value factor while touchpad scrolling - /// - public double TouchpadScrollDeltaFactor - { - get { return (double)GetValue(TouchpadScrollDeltaFactorProperty); } - set { SetValue(TouchpadScrollDeltaFactorProperty, value); } - } - - /// - /// Always handle mouse wheel scrolling.
- /// (Especially in "TextBox") - ///
- public bool AlwaysHandleMouseWheelScrolling - { - get { return (bool)GetValue(AlwaysHandleMouseWheelScrollingProperty); } - set { SetValue(AlwaysHandleMouseWheelScrollingProperty, value); } - } - - - - - - - - - /// - /// The key needed set a read-only property - /// - public static readonly DependencyPropertyKey HorizontalOffsetTargetPropertyKey = - DependencyProperty.RegisterReadOnly(nameof(HorizontalOffsetTarget), typeof(double), typeof(ScrollViewer), new PropertyMetadata(0.0)); - - /// - /// The key needed set a read-only property - /// - public static readonly DependencyPropertyKey VerticalOffsetTargetPropertyKey = - DependencyProperty.RegisterReadOnly(nameof(VerticalOffsetTarget), typeof(double), typeof(ScrollViewer), new PropertyMetadata(0.0)); - - /// - /// The key needed set a read-only property - /// - public static readonly DependencyProperty HorizontalOffsetTargetProperty = - HorizontalOffsetTargetPropertyKey.DependencyProperty; - - /// - /// The key needed set a read-only property - /// - public static readonly DependencyProperty VerticalOffsetTargetProperty = - VerticalOffsetTargetPropertyKey.DependencyProperty; - - - - /// - /// Get value of ScrollWithWheelDelta property - /// - /// - /// - public static bool GetScrollWithWheelDelta(DependencyObject obj) - { - return (bool)obj.GetValue(ScrollWithWheelDeltaProperty); - } - - /// - /// Set value of ScrollWithWheelDelta property - /// - /// - /// - public static void SetScrollWithWheelDelta(DependencyObject obj, bool value) - { - obj.SetValue(ScrollWithWheelDeltaProperty, value); - } - - /// - /// Get value of EnableScrollingAnimation property - /// - /// - /// - public static bool GetEnableScrollingAnimation(DependencyObject obj) - { - return (bool)obj.GetValue(EnableScrollingAnimationProperty); - } - - /// - /// Set value of EnableScrollingAnimation property - /// - /// - /// - public static void SetEnableScrollingAnimation(DependencyObject obj, bool value) - { - obj.SetValue(EnableScrollingAnimationProperty, value); - } - - /// - /// Get value of ScrollingAnimationDuration property - /// - /// - /// - public static Duration GetScrollingAnimationDuration(DependencyObject obj) - { - return (Duration)obj.GetValue(ScrollingAnimationDurationProperty); - } - - /// - /// Set value of ScrollingAnimationDuration property - /// - /// - /// - public static void SetScrollingAnimationDuration(DependencyObject obj, Duration value) - { - obj.SetValue(ScrollingAnimationDurationProperty, value); - } - - - /// - /// Set value of AlwaysHandleMouseWheelScrolling property - /// - /// - /// - public static bool GetAlwaysHandleMouseWheelScrolling(DependencyObject obj) - { - return (bool)obj.GetValue(AlwaysHandleMouseWheelScrollingProperty); - } - - /// - /// Get value of AlwaysHandleMouseWheelScrolling property - /// - /// - /// - public static void SetAlwaysHandleMouseWheelScrolling(DependencyObject obj, bool value) - { - obj.SetValue(AlwaysHandleMouseWheelScrollingProperty, value); - } - - - /// - /// The DependencyProperty of property. - /// - public static readonly DependencyProperty ScrollWithWheelDeltaProperty = - DependencyProperty.RegisterAttached(nameof(ScrollWithWheelDelta), typeof(bool), typeof(ScrollViewer), - new FrameworkPropertyMetadata(true, FrameworkPropertyMetadataOptions.Inherits)); - - /// - /// The DependencyProperty of property. - /// - public static readonly DependencyProperty EnableScrollingAnimationProperty = - DependencyProperty.RegisterAttached(nameof(EnableScrollingAnimation), typeof(bool), typeof(ScrollViewer), - new FrameworkPropertyMetadata(true, FrameworkPropertyMetadataOptions.Inherits)); - - /// - /// The DependencyProperty of property. - /// - public static readonly DependencyProperty ScrollingAnimationDurationProperty = - DependencyProperty.RegisterAttached(nameof(ScrollingAnimationDuration), typeof(Duration), typeof(ScrollViewer), - new FrameworkPropertyMetadata(new Duration(TimeSpan.FromMilliseconds(250)), FrameworkPropertyMetadataOptions.Inherits), ValidateScrollingAnimationDuration); - - /// - /// The DependencyProperty of property - /// - public static readonly DependencyProperty AlwaysHandleMouseWheelScrollingProperty = - DependencyProperty.RegisterAttached(nameof(AlwaysHandleMouseWheelScrolling), typeof(bool), typeof(ScrollViewer), new FrameworkPropertyMetadata(true, FrameworkPropertyMetadataOptions.Inherits)); - - /// - /// The DependencyProperty of property - /// - public static readonly DependencyProperty MouseScrollDeltaFactorProperty = - DependencyProperty.Register(nameof(MouseScrollDeltaFactor), typeof(double), typeof(ScrollViewer), new PropertyMetadata(1.0)); - - /// - /// The DependencyProperty of property - /// - public static readonly DependencyProperty TouchpadScrollDeltaFactorProperty = - DependencyProperty.Register(nameof(TouchpadScrollDeltaFactor), typeof(double), typeof(ScrollViewer), new PropertyMetadata(1.0)); - - private static bool ValidateScrollingAnimationDuration(object value) - => value is Duration duration && duration.HasTimeSpan; - } + } + + private delegate bool GetBool(ScrollViewer scrollViewer); + private static readonly GetBool _propertyHandlesMouseWheelScrollingGetter; + private static readonly IEasingFunction _scrollingAnimationEase = new CubicEase() { EasingMode = EasingMode.EaseOut }; + private const long _millisecondsBetweenTouchpadScrolling = 100; + + private bool _animationRunning = false; + private int _lastScrollDelta = 0; + private int _lastVerticalScrollingDelta = 0; + private int _lastHorizontalScrollingDelta = 0; + private long _lastScrollingTick; + + private FrameworkElement? _scrollContentPresenter; + + /// + public override void OnApplyTemplate() + { + base.OnApplyTemplate(); + + _scrollContentPresenter = GetTemplateChild("PART_ScrollContentPresenter") as FrameworkElement; + } + + private void CoreScrollWithWheelDelta(MouseWheelEventArgs e) + { + if (e.Handled) + { + return; + } + + if (!AlwaysHandleMouseWheelScrolling && + !_propertyHandlesMouseWheelScrollingGetter.Invoke(this)) + { + return; + } + + bool vertical = ExtentHeight > 0; + bool horizontal = ExtentWidth > 0; + + var tickCount = Environment.TickCount; + var isTouchpadScrolling = + e.Delta % Mouse.MouseWheelDeltaForOneLine != 0 || + (tickCount - _lastScrollingTick < _millisecondsBetweenTouchpadScrolling && _lastScrollDelta % Mouse.MouseWheelDeltaForOneLine != 0); + + double scrollDelta = e.Delta; + + if (isTouchpadScrolling) + { + // touchpad 应该滚动更慢一些, 所以这里预先除以一个合适的值 + scrollDelta /= 2; + + // + scrollDelta *= TouchpadScrollDeltaFactor; + } + else + { + scrollDelta *= MouseScrollDeltaFactor; + } + + if (vertical) + { + if (ScrollInfo is IScrollInfo scrollInfo) + { + // 考虑到 VirtualizingPanel 可能是虚拟的大小, 所以这里需要校正 Delta + scrollDelta *= scrollInfo.ViewportHeight / (_scrollContentPresenter?.ActualHeight ?? ActualHeight); + } + + var sameDirectionAsLast = Math.Sign(e.Delta) == Math.Sign(_lastVerticalScrollingDelta); + var nowOffset = sameDirectionAsLast && _animationRunning ? VerticalOffsetTarget : VerticalOffset; + var newOffset = nowOffset - scrollDelta; + + if (newOffset < 0) + newOffset = 0; + if (newOffset > ScrollableHeight) + newOffset = ScrollableHeight; + + SetValue(VerticalOffsetTargetPropertyKey, newOffset); + BeginAnimation(ScrollViewerUtils.VerticalOffsetProperty, null); + + if (!EnableScrollingAnimation || isTouchpadScrolling) + { + ScrollToVerticalOffset(newOffset); + } + else + { + var diff = newOffset - VerticalOffset; + var absDiff = Math.Abs(diff); + var duration = ScrollingAnimationDuration; + if (absDiff < Mouse.MouseWheelDeltaForOneLine) + { + duration = new Duration(TimeSpan.FromTicks((long)(duration.TimeSpan.Ticks * absDiff / Mouse.MouseWheelDeltaForOneLine))); + } + + DoubleAnimation doubleAnimation = new DoubleAnimation() { + EasingFunction = _scrollingAnimationEase, + Duration = duration, + From = VerticalOffset, + To = newOffset, + }; + + doubleAnimation.Completed += DoubleAnimation_Completed; + + _animationRunning = true; + BeginAnimation(ScrollViewerUtils.VerticalOffsetProperty, doubleAnimation, HandoffBehavior.SnapshotAndReplace); + } + + _lastVerticalScrollingDelta = e.Delta; + } + else if (horizontal) + { + if (ScrollInfo is IScrollInfo scrollInfo) + { + // 考虑到 VirtualizingPanel 可能是虚拟的大小, 所以这里需要校正 Delta + scrollDelta *= scrollInfo.ViewportWidth / (_scrollContentPresenter?.ActualWidth ?? ActualWidth); + } + + var sameDirectionAsLast = Math.Sign(e.Delta) == Math.Sign(_lastHorizontalScrollingDelta); + var nowOffset = sameDirectionAsLast && _animationRunning ? HorizontalOffsetTarget : HorizontalOffset; + var newOffset = nowOffset - scrollDelta; + + if (newOffset < 0) + newOffset = 0; + if (newOffset > ScrollableWidth) + newOffset = ScrollableWidth; + + SetValue(HorizontalOffsetTargetPropertyKey, newOffset); + BeginAnimation(ScrollViewerUtils.HorizontalOffsetProperty, null); + + if (!EnableScrollingAnimation || isTouchpadScrolling) + { + ScrollToHorizontalOffset(newOffset); + } + else + { + var diff = newOffset - HorizontalOffset; + var absDiff = Math.Abs(diff); + var duration = ScrollingAnimationDuration; + if (absDiff < Mouse.MouseWheelDeltaForOneLine) + { + duration = new Duration(TimeSpan.FromTicks((long)(duration.TimeSpan.Ticks * absDiff / Mouse.MouseWheelDeltaForOneLine))); + } + + DoubleAnimation doubleAnimation = new DoubleAnimation() { + EasingFunction = _scrollingAnimationEase, + Duration = duration, + From = HorizontalOffset, + To = newOffset, + }; + + doubleAnimation.Completed += DoubleAnimation_Completed; + + _animationRunning = true; + BeginAnimation(ScrollViewerUtils.HorizontalOffsetProperty, doubleAnimation, HandoffBehavior.SnapshotAndReplace); + } + + _lastHorizontalScrollingDelta = e.Delta; + } + + _lastScrollingTick = tickCount; + _lastScrollDelta = e.Delta; + + e.Handled = true; + } + + private void DoubleAnimation_Completed(object? sender, EventArgs e) + { + _animationRunning = false; + } + + /// + protected override void OnMouseWheel(MouseWheelEventArgs e) + { + if (!ScrollWithWheelDelta) + { + base.OnMouseWheel(e); + } + else + { + Debug.WriteLine(e.Delta); + + CoreScrollWithWheelDelta(e); + } + } + + /// + /// The horizontal offset of scrolling target + /// + public double HorizontalOffsetTarget { + get { return (double)GetValue(HorizontalOffsetTargetProperty); } + } + + /// + /// The vertical offset of scrolling target + /// + public double VerticalOffsetTarget { + get { return (double)GetValue(VerticalOffsetTargetProperty); } + } + + /// + /// Scroll with wheel delta instead of scrolling fixed number of lines + /// + public bool ScrollWithWheelDelta { + get { return (bool)GetValue(ScrollWithWheelDeltaProperty); } + set { SetValue(ScrollWithWheelDeltaProperty, value); } + } + + /// + /// Enable scrolling animation while using mouse
+ /// You need to set ScrollWithWheelDelta to true to use this + ///
+ public bool EnableScrollingAnimation { + get { return (bool)GetValue(EnableScrollingAnimationProperty); } + set { SetValue(EnableScrollingAnimationProperty, value); } + } + + /// + /// Scrolling animation duration + /// + public Duration ScrollingAnimationDuration { + get { return (Duration)GetValue(ScrollingAnimationDurationProperty); } + set { SetValue(ScrollingAnimationDurationProperty, value); } + } + + /// + /// Delta value factor while mouse scrolling + /// + public double MouseScrollDeltaFactor { + get { return (double)GetValue(MouseScrollDeltaFactorProperty); } + set { SetValue(MouseScrollDeltaFactorProperty, value); } + } + + /// + /// Delta value factor while touchpad scrolling + /// + public double TouchpadScrollDeltaFactor { + get { return (double)GetValue(TouchpadScrollDeltaFactorProperty); } + set { SetValue(TouchpadScrollDeltaFactorProperty, value); } + } + + /// + /// Always handle mouse wheel scrolling.
+ /// (Especially in "TextBox") + ///
+ public bool AlwaysHandleMouseWheelScrolling { + get { return (bool)GetValue(AlwaysHandleMouseWheelScrollingProperty); } + set { SetValue(AlwaysHandleMouseWheelScrollingProperty, value); } + } + + + + + + + + + /// + /// The key needed set a read-only property + /// + public static readonly DependencyPropertyKey HorizontalOffsetTargetPropertyKey = + DependencyProperty.RegisterReadOnly(nameof(HorizontalOffsetTarget), typeof(double), typeof(ScrollViewer), new PropertyMetadata(0.0)); + + /// + /// The key needed set a read-only property + /// + public static readonly DependencyPropertyKey VerticalOffsetTargetPropertyKey = + DependencyProperty.RegisterReadOnly(nameof(VerticalOffsetTarget), typeof(double), typeof(ScrollViewer), new PropertyMetadata(0.0)); + + /// + /// The key needed set a read-only property + /// + public static readonly DependencyProperty HorizontalOffsetTargetProperty = + HorizontalOffsetTargetPropertyKey.DependencyProperty; + + /// + /// The key needed set a read-only property + /// + public static readonly DependencyProperty VerticalOffsetTargetProperty = + VerticalOffsetTargetPropertyKey.DependencyProperty; + + + + /// + /// Get value of ScrollWithWheelDelta property + /// + /// + /// + public static bool GetScrollWithWheelDelta(DependencyObject obj) + { + return (bool)obj.GetValue(ScrollWithWheelDeltaProperty); + } + + /// + /// Set value of ScrollWithWheelDelta property + /// + /// + /// + public static void SetScrollWithWheelDelta(DependencyObject obj, bool value) + { + obj.SetValue(ScrollWithWheelDeltaProperty, value); + } + + /// + /// Get value of EnableScrollingAnimation property + /// + /// + /// + public static bool GetEnableScrollingAnimation(DependencyObject obj) + { + return (bool)obj.GetValue(EnableScrollingAnimationProperty); + } + + /// + /// Set value of EnableScrollingAnimation property + /// + /// + /// + public static void SetEnableScrollingAnimation(DependencyObject obj, bool value) + { + obj.SetValue(EnableScrollingAnimationProperty, value); + } + + /// + /// Get value of ScrollingAnimationDuration property + /// + /// + /// + public static Duration GetScrollingAnimationDuration(DependencyObject obj) + { + return (Duration)obj.GetValue(ScrollingAnimationDurationProperty); + } + + /// + /// Set value of ScrollingAnimationDuration property + /// + /// + /// + public static void SetScrollingAnimationDuration(DependencyObject obj, Duration value) + { + obj.SetValue(ScrollingAnimationDurationProperty, value); + } + + + /// + /// Set value of AlwaysHandleMouseWheelScrolling property + /// + /// + /// + public static bool GetAlwaysHandleMouseWheelScrolling(DependencyObject obj) + { + return (bool)obj.GetValue(AlwaysHandleMouseWheelScrollingProperty); + } + + /// + /// Get value of AlwaysHandleMouseWheelScrolling property + /// + /// + /// + public static void SetAlwaysHandleMouseWheelScrolling(DependencyObject obj, bool value) + { + obj.SetValue(AlwaysHandleMouseWheelScrollingProperty, value); + } + + + /// + /// The DependencyProperty of property. + /// + public static readonly DependencyProperty ScrollWithWheelDeltaProperty = + DependencyProperty.RegisterAttached(nameof(ScrollWithWheelDelta), typeof(bool), typeof(ScrollViewer), + new FrameworkPropertyMetadata(true, FrameworkPropertyMetadataOptions.Inherits)); + + /// + /// The DependencyProperty of property. + /// + public static readonly DependencyProperty EnableScrollingAnimationProperty = + DependencyProperty.RegisterAttached(nameof(EnableScrollingAnimation), typeof(bool), typeof(ScrollViewer), + new FrameworkPropertyMetadata(true, FrameworkPropertyMetadataOptions.Inherits)); + + /// + /// The DependencyProperty of property. + /// + public static readonly DependencyProperty ScrollingAnimationDurationProperty = + DependencyProperty.RegisterAttached(nameof(ScrollingAnimationDuration), typeof(Duration), typeof(ScrollViewer), + new FrameworkPropertyMetadata(new Duration(TimeSpan.FromMilliseconds(250)), FrameworkPropertyMetadataOptions.Inherits), ValidateScrollingAnimationDuration); + + /// + /// The DependencyProperty of property + /// + public static readonly DependencyProperty AlwaysHandleMouseWheelScrollingProperty = + DependencyProperty.RegisterAttached(nameof(AlwaysHandleMouseWheelScrolling), typeof(bool), typeof(ScrollViewer), new FrameworkPropertyMetadata(true, FrameworkPropertyMetadataOptions.Inherits)); + + /// + /// The DependencyProperty of property + /// + public static readonly DependencyProperty MouseScrollDeltaFactorProperty = + DependencyProperty.Register(nameof(MouseScrollDeltaFactor), typeof(double), typeof(ScrollViewer), new PropertyMetadata(1.0)); + + /// + /// The DependencyProperty of property + /// + public static readonly DependencyProperty TouchpadScrollDeltaFactorProperty = + DependencyProperty.Register(nameof(TouchpadScrollDeltaFactor), typeof(double), typeof(ScrollViewer), new PropertyMetadata(1.0)); + + private static bool ValidateScrollingAnimationDuration(object value) + => value is Duration duration && duration.HasTimeSpan; + } } diff --git a/EleCho.WpfSuite/MathHelper.cs b/EleCho.WpfSuite/MathHelper.cs index e82b1f018..cb8ca4e30 100644 --- a/EleCho.WpfSuite/MathHelper.cs +++ b/EleCho.WpfSuite/MathHelper.cs @@ -8,68 +8,68 @@ using System.Windows; namespace EleCho.WpfSuite { - internal static class MathHelper - { - internal const double DBL_EPSILON = 2.2204460492503131e-016; + internal static class MathHelper + { + internal const double DBL_EPSILON = 2.2204460492503131e-016; - public static bool AreClose(double value1, double value2) => - // ReSharper disable once CompareOfFloatsByEqualityOperator - value1 == value2 || IsVerySmall(value1 - value2); + public static bool AreClose(double value1, double value2) => + // ReSharper disable once CompareOfFloatsByEqualityOperator + value1 == value2 || IsVerySmall(value1 - value2); - public static double Lerp(double x, double y, double alpha) => x * (1.0 - alpha) + y * alpha; + public static double Lerp(double x, double y, double alpha) => x * (1.0 - alpha) + y * alpha; - public static bool IsVerySmall(double value) => Math.Abs(value) < 1E-06; + public static bool IsVerySmall(double value) => Math.Abs(value) < 1E-06; - public static bool IsZero(double value) => Math.Abs(value) < 10.0 * DBL_EPSILON; + public static bool IsZero(double value) => Math.Abs(value) < 10.0 * DBL_EPSILON; - public static bool IsFiniteDouble(double x) => !double.IsInfinity(x) && !double.IsNaN(x); + public static bool IsFiniteDouble(double x) => !double.IsInfinity(x) && !double.IsNaN(x); - public static double DoubleFromMantissaAndExponent(double x, int exp) => x * Math.Pow(2.0, exp); + public static double DoubleFromMantissaAndExponent(double x, int exp) => x * Math.Pow(2.0, exp); - public static bool GreaterThan(double value1, double value2) => value1 > value2 && !AreClose(value1, value2); + public static bool GreaterThan(double value1, double value2) => value1 > value2 && !AreClose(value1, value2); - public static bool GreaterThanOrClose(double value1, double value2) - { - if (value1 <= value2) - { - return AreClose(value1, value2); - } - return true; - } + public static bool GreaterThanOrClose(double value1, double value2) + { + if (value1 <= value2) + { + return AreClose(value1, value2); + } + return true; + } - public static double Hypotenuse(double x, double y) => Math.Sqrt(x * x + y * y); + public static double Hypotenuse(double x, double y) => Math.Sqrt(x * x + y * y); - public static bool LessThan(double value1, double value2) => value1 < value2 && !AreClose(value1, value2); + public static bool LessThan(double value1, double value2) => value1 < value2 && !AreClose(value1, value2); - public static bool LessThanOrClose(double value1, double value2) - { - if (value1 >= value2) - { - return AreClose(value1, value2); - } - return true; - } + public static bool LessThanOrClose(double value1, double value2) + { + if (value1 >= value2) + { + return AreClose(value1, value2); + } + return true; + } - public static double EnsureRange(double value, double? min, double? max) - { - if (min.HasValue && value < min.Value) - { - return min.Value; - } - if (max.HasValue && value > max.Value) - { - return max.Value; - } - return value; - } + public static double EnsureRange(double value, double? min, double? max) + { + if (min.HasValue && value < min.Value) + { + return min.Value; + } + if (max.HasValue && value > max.Value) + { + return max.Value; + } + return value; + } - public static double SafeDivide(double lhs, double rhs, double fallback) - { - if (!IsVerySmall(rhs)) - { - return lhs / rhs; - } - return fallback; - } - } + public static double SafeDivide(double lhs, double rhs, double fallback) + { + if (!IsVerySmall(rhs)) + { + return lhs / rhs; + } + return fallback; + } + } } diff --git a/EleCho.WpfSuite/Themes/Generic.xaml b/EleCho.WpfSuite/Themes/Generic.xaml index 6b82c0846..be8b8bb3a 100644 --- a/EleCho.WpfSuite/Themes/Generic.xaml +++ b/EleCho.WpfSuite/Themes/Generic.xaml @@ -1,7 +1,7 @@ - - - - + + + + diff --git a/EleCho.WpfSuite/Utilities/ScrollViewerUtils.cs b/EleCho.WpfSuite/Utilities/ScrollViewerUtils.cs index d204febb6..88f3f6023 100644 --- a/EleCho.WpfSuite/Utilities/ScrollViewerUtils.cs +++ b/EleCho.WpfSuite/Utilities/ScrollViewerUtils.cs @@ -5,116 +5,116 @@ using System.Windows.Controls.Primitives; namespace EleCho.WpfSuite { - /// - /// ScrollViewer Utilities - /// - public static class ScrollViewerUtils - { - /// - /// Get value of VerticalOffset property - /// - /// - /// - public static double GetVerticalOffset(DependencyObject d) - { - if (d is ScrollViewer sv) - { - return sv.VerticalOffset; - } - else if (d is ScrollContentPresenter scp) - { - return scp.VerticalOffset; - } + /// + /// ScrollViewer Utilities + /// + public static class ScrollViewerUtils + { + /// + /// Get value of VerticalOffset property + /// + /// + /// + public static double GetVerticalOffset(DependencyObject d) + { + if (d is ScrollViewer sv) + { + return sv.VerticalOffset; + } + else if (d is ScrollContentPresenter scp) + { + return scp.VerticalOffset; + } - return (double)d.GetValue(VerticalOffsetProperty); - } + return (double)d.GetValue(VerticalOffsetProperty); + } - /// - /// Set value of VerticalOffset property - /// - /// - /// - public static void SetVerticalOffset(DependencyObject obj, double value) - { - obj.SetValue(VerticalOffsetProperty, value); - } + /// + /// Set value of VerticalOffset property + /// + /// + /// + public static void SetVerticalOffset(DependencyObject obj, double value) + { + obj.SetValue(VerticalOffsetProperty, value); + } - /// - /// Get value of HorizontalOffset property - /// - /// - /// - public static double GetHorizontalOffset(DependencyObject d) - { - if (d is ScrollViewer sv) - { - return sv.HorizontalOffset; - } - else if (d is ScrollContentPresenter scp) - { - return scp.HorizontalOffset; - } + /// + /// Get value of HorizontalOffset property + /// + /// + /// + public static double GetHorizontalOffset(DependencyObject d) + { + if (d is ScrollViewer sv) + { + return sv.HorizontalOffset; + } + else if (d is ScrollContentPresenter scp) + { + return scp.HorizontalOffset; + } - return (double)d.GetValue(HorizontalOffsetProperty); - } + return (double)d.GetValue(HorizontalOffsetProperty); + } - /// - /// Set value of HorizontalOffset property - /// - /// - /// - public static void SetHorizontalOffset(DependencyObject obj, double value) - { - obj.SetValue(HorizontalOffsetProperty, value); - } + /// + /// Set value of HorizontalOffset property + /// + /// + /// + public static void SetHorizontalOffset(DependencyObject obj, double value) + { + obj.SetValue(HorizontalOffsetProperty, value); + } - /// - /// The DependencyProperty of VerticalOffset property - /// - public static readonly DependencyProperty VerticalOffsetProperty = - DependencyProperty.RegisterAttached("VerticalOffset", typeof(double), typeof(ScrollViewerUtils), new PropertyMetadata(0.0, VerticalOffsetChangedCallback)); + /// + /// The DependencyProperty of VerticalOffset property + /// + public static readonly DependencyProperty VerticalOffsetProperty = + DependencyProperty.RegisterAttached("VerticalOffset", typeof(double), typeof(ScrollViewerUtils), new PropertyMetadata(0.0, VerticalOffsetChangedCallback)); - /// - /// The DependencyProperty of HorizontalOffset property - /// - public static readonly DependencyProperty HorizontalOffsetProperty = - DependencyProperty.RegisterAttached("HorizontalOffset", typeof(double), typeof(ScrollViewerUtils), new PropertyMetadata(0.0, HorizontalOffsetChangedCallback)); + /// + /// The DependencyProperty of HorizontalOffset property + /// + public static readonly DependencyProperty HorizontalOffsetProperty = + DependencyProperty.RegisterAttached("HorizontalOffset", typeof(double), typeof(ScrollViewerUtils), new PropertyMetadata(0.0, HorizontalOffsetChangedCallback)); - private static void VerticalOffsetChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - if (e.NewValue is not double offset) - { - return; - } + private static void VerticalOffsetChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + if (e.NewValue is not double offset) + { + return; + } - if (d is ScrollViewer sv) - { - sv.ScrollToVerticalOffset(offset); - } - else if (d is ScrollContentPresenter scp) - { - scp.SetVerticalOffset(offset); - } - } + if (d is ScrollViewer sv) + { + sv.ScrollToVerticalOffset(offset); + } + else if (d is ScrollContentPresenter scp) + { + scp.SetVerticalOffset(offset); + } + } - private static void HorizontalOffsetChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - if (e.NewValue is not double offset) - { - return; - } + private static void HorizontalOffsetChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + if (e.NewValue is not double offset) + { + return; + } - if (d is ScrollViewer sv) - { - sv.ScrollToHorizontalOffset(offset); - } - else if (d is ScrollContentPresenter scp) - { - scp.SetHorizontalOffset(offset); - } - } - } + if (d is ScrollViewer sv) + { + sv.ScrollToHorizontalOffset(offset); + } + else if (d is ScrollContentPresenter scp) + { + scp.SetHorizontalOffset(offset); + } + } + } } diff --git a/EleCho.WpfSuite/ValueConverters/FallbackConverter.cs b/EleCho.WpfSuite/ValueConverters/FallbackConverter.cs index 6741b7461..89aaf17e7 100644 --- a/EleCho.WpfSuite/ValueConverters/FallbackConverter.cs +++ b/EleCho.WpfSuite/ValueConverters/FallbackConverter.cs @@ -4,23 +4,23 @@ using System.Windows; namespace EleCho.WpfSuite { - /// - /// Fallback between multiple values, return the first non-null value - /// - public class FallbackConverter : SingletonMultiValueConverterBase - { - /// - public override object? Convert(object?[] values, Type targetType, object? parameter, CultureInfo culture) - { - foreach (var value in values) - { - if (value is not null && - value != DependencyProperty.UnsetValue) - return value; - } + /// + /// Fallback between multiple values, return the first non-null value + /// + public class FallbackConverter : SingletonMultiValueConverterBase + { + /// + public override object? Convert(object?[] values, Type targetType, object? parameter, CultureInfo culture) + { + foreach (var value in values) + { + if (value is not null && + value != DependencyProperty.UnsetValue) + return value; + } - return null; - } - } + return null; + } + } } diff --git a/EleCho.WpfSuite/ValueConverters/MultiValueConverterBase.cs b/EleCho.WpfSuite/ValueConverters/MultiValueConverterBase.cs index 72a9ebe04..63489213a 100644 --- a/EleCho.WpfSuite/ValueConverters/MultiValueConverterBase.cs +++ b/EleCho.WpfSuite/ValueConverters/MultiValueConverterBase.cs @@ -4,19 +4,19 @@ using System.Windows.Data; namespace EleCho.WpfSuite { - /// - /// Base class of multi value converter - /// - /// - public abstract class MultiValueConverterBase : IMultiValueConverter - { - /// - public abstract object? Convert(object?[] values, Type targetType, object? parameter, CultureInfo culture); + /// + /// Base class of multi value converter + /// + /// + public abstract class MultiValueConverterBase : IMultiValueConverter + { + /// + public abstract object? Convert(object?[] values, Type targetType, object? parameter, CultureInfo culture); - /// - public virtual object?[] ConvertBack(object? value, Type[] targetTypes, object? parameter, CultureInfo culture) - { - throw new NotSupportedException(); - } - } + /// + public virtual object?[] ConvertBack(object? value, Type[] targetTypes, object? parameter, CultureInfo culture) + { + throw new NotSupportedException(); + } + } } diff --git a/EleCho.WpfSuite/ValueConverters/SingletonMultiValueConverterBase.cs b/EleCho.WpfSuite/ValueConverters/SingletonMultiValueConverterBase.cs index 538ea2f15..b436fcbeb 100644 --- a/EleCho.WpfSuite/ValueConverters/SingletonMultiValueConverterBase.cs +++ b/EleCho.WpfSuite/ValueConverters/SingletonMultiValueConverterBase.cs @@ -1,17 +1,17 @@ namespace EleCho.WpfSuite { - /// - /// Base class of singleton multi value converter - /// - /// - public abstract class SingletonMultiValueConverterBase : MultiValueConverterBase - where TSelf : SingletonMultiValueConverterBase, new() - { - private static TSelf? _instance = null; + /// + /// Base class of singleton multi value converter + /// + /// + public abstract class SingletonMultiValueConverterBase : MultiValueConverterBase + where TSelf : SingletonMultiValueConverterBase, new() + { + private static TSelf? _instance = null; - /// - /// Get an instance of - /// - public static TSelf Instance => _instance ?? new(); - } + /// + /// Get an instance of + /// + public static TSelf Instance => _instance ?? new(); + } }