Browse Source

Fix Format

pull/3234/head
SlimeNull 11 months ago
parent
commit
8179722d01
  1. 95
      EleCho.WpfSuite/Controls/ListBox.cs
  2. 16
      EleCho.WpfSuite/Controls/ListBoxResources.xaml
  3. 107
      EleCho.WpfSuite/Controls/ListView.cs
  4. 16
      EleCho.WpfSuite/Controls/ListViewResources.xaml
  5. 848
      EleCho.WpfSuite/Controls/ScrollViewer.cs
  6. 102
      EleCho.WpfSuite/MathHelper.cs
  7. 8
      EleCho.WpfSuite/Themes/Generic.xaml
  8. 196
      EleCho.WpfSuite/Utilities/ScrollViewerUtils.cs
  9. 34
      EleCho.WpfSuite/ValueConverters/FallbackConverter.cs
  10. 28
      EleCho.WpfSuite/ValueConverters/MultiValueConverterBase.cs
  11. 26
      EleCho.WpfSuite/ValueConverters/SingletonMultiValueConverterBase.cs

95
EleCho.WpfSuite/Controls/ListBox.cs

@ -14,59 +14,56 @@ using System.Windows.Shapes; @@ -14,59 +14,56 @@ using System.Windows.Shapes;
namespace EleCho.WpfSuite
{
/// <inheritdoc/>
public class ListBox : System.Windows.Controls.ListBox
{
static ListBox()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(ListBox), new FrameworkPropertyMetadata(typeof(ListBox)));
}
/// <inheritdoc/>
public class ListBox : System.Windows.Controls.ListBox
{
static ListBox()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(ListBox), new FrameworkPropertyMetadata(typeof(ListBox)));
}
/// <summary>
/// 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.
/// </summary>
public CornerRadius CornerRadius
{
get { return (CornerRadius)GetValue(CornerRadiusProperty); }
set { SetValue(CornerRadiusProperty, value); }
}
/// <summary>
/// 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.
/// </summary>
public CornerRadius CornerRadius {
get { return (CornerRadius)GetValue(CornerRadiusProperty); }
set { SetValue(CornerRadiusProperty, value); }
}
/// <summary>
/// Background when disabled
/// </summary>
public Brush DisabledBackground
{
get { return (Brush)GetValue(DisabledBackgroundProperty); }
set { SetValue(DisabledBackgroundProperty, value); }
}
/// <summary>
/// Background when disabled
/// </summary>
public Brush DisabledBackground {
get { return (Brush)GetValue(DisabledBackgroundProperty); }
set { SetValue(DisabledBackgroundProperty, value); }
}
/// <summary>
/// BorderBrush when pressed by mouse
/// </summary>
public Brush DisabledBorderBrush
{
get { return (Brush)GetValue(DisabledBorderBrushProperty); }
set { SetValue(DisabledBorderBrushProperty, value); }
}
/// <summary>
/// BorderBrush when pressed by mouse
/// </summary>
public Brush DisabledBorderBrush {
get { return (Brush)GetValue(DisabledBorderBrushProperty); }
set { SetValue(DisabledBorderBrushProperty, value); }
}
/// <summary>
/// DependencyProperty of <see cref="CornerRadius"/> property
/// </summary>
public static readonly DependencyProperty CornerRadiusProperty =
System.Windows.Controls.Border.CornerRadiusProperty.AddOwner(typeof(ListBox));
/// <summary>
/// DependencyProperty of <see cref="CornerRadius"/> property
/// </summary>
public static readonly DependencyProperty CornerRadiusProperty =
System.Windows.Controls.Border.CornerRadiusProperty.AddOwner(typeof(ListBox));
/// <summary>
/// The DependencyProperty of <see cref="DisabledBackground"/> property
/// </summary>
public static readonly DependencyProperty DisabledBackgroundProperty =
DependencyProperty.Register(nameof(DisabledBackground), typeof(Brush), typeof(ListBox), new FrameworkPropertyMetadata(null));
/// <summary>
/// The DependencyProperty of <see cref="DisabledBackground"/> property
/// </summary>
public static readonly DependencyProperty DisabledBackgroundProperty =
DependencyProperty.Register(nameof(DisabledBackground), typeof(Brush), typeof(ListBox), new FrameworkPropertyMetadata(null));
/// <summary>
/// The DependencyProperty of <see cref="DisabledBorderBrush"/> property
/// </summary>
public static readonly DependencyProperty DisabledBorderBrushProperty =
DependencyProperty.Register(nameof(DisabledBorderBrush), typeof(Brush), typeof(ListBox), new FrameworkPropertyMetadata(null));
}
/// <summary>
/// The DependencyProperty of <see cref="DisabledBorderBrush"/> property
/// </summary>
public static readonly DependencyProperty DisabledBorderBrushProperty =
DependencyProperty.Register(nameof(DisabledBorderBrush), typeof(Brush), typeof(ListBox), new FrameworkPropertyMetadata(null));
}
}

16
EleCho.WpfSuite/Controls/ListBoxResources.xaml

@ -23,19 +23,19 @@ @@ -23,19 +23,19 @@
<Setter.Value>
<ControlTemplate TargetType="{x:Type ws:ListBox}">
<Border x:Name="Part_BD"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="{TemplateBinding CornerRadius}"
Padding="1"
SnapsToDevicePixels="true">
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="{TemplateBinding CornerRadius}"
Padding="1"
SnapsToDevicePixels="true">
<ws:ScrollViewer x:Name="PART_Content"
Focusable="false" Padding="{TemplateBinding Padding}">
<ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
</ws:ScrollViewer>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="False">
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter TargetName="Part_BD" Property="Background">
<Setter.Value>
<MultiBinding Converter="{x:Static ws:FallbackConverter.Instance}">

107
EleCho.WpfSuite/Controls/ListView.cs

@ -3,61 +3,58 @@ using System.Windows.Media; @@ -3,61 +3,58 @@ using System.Windows.Media;
namespace EleCho.WpfSuite
{
/// <inheritdoc/>
public class ListView : System.Windows.Controls.ListView
{
static ListView()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(ListView), new FrameworkPropertyMetadata(typeof(ListView)));
}
/// <summary>
/// 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.
/// </summary>
public CornerRadius CornerRadius
{
get { return (CornerRadius)GetValue(CornerRadiusProperty); }
set { SetValue(CornerRadiusProperty, value); }
}
/// <summary>
/// Background when disabled
/// </summary>
public Brush DisabledBackground
{
get { return (Brush)GetValue(DisabledBackgroundProperty); }
set { SetValue(DisabledBackgroundProperty, value); }
}
/// <summary>
/// BorderBrush when pressed by mouse
/// </summary>
public Brush DisabledBorderBrush
{
get { return (Brush)GetValue(DisabledBorderBrushProperty); }
set { SetValue(DisabledBorderBrushProperty, value); }
}
/// <summary>
/// DependencyProperty of <see cref="CornerRadius"/> property
/// </summary>
public static readonly DependencyProperty CornerRadiusProperty =
/// <inheritdoc/>
public class ListView : System.Windows.Controls.ListView
{
static ListView()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(ListView), new FrameworkPropertyMetadata(typeof(ListView)));
}
/// <summary>
/// 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.
/// </summary>
public CornerRadius CornerRadius {
get { return (CornerRadius)GetValue(CornerRadiusProperty); }
set { SetValue(CornerRadiusProperty, value); }
}
/// <summary>
/// Background when disabled
/// </summary>
public Brush DisabledBackground {
get { return (Brush)GetValue(DisabledBackgroundProperty); }
set { SetValue(DisabledBackgroundProperty, value); }
}
/// <summary>
/// BorderBrush when pressed by mouse
/// </summary>
public Brush DisabledBorderBrush {
get { return (Brush)GetValue(DisabledBorderBrushProperty); }
set { SetValue(DisabledBorderBrushProperty, value); }
}
/// <summary>
/// DependencyProperty of <see cref="CornerRadius"/> property
/// </summary>
public static readonly DependencyProperty CornerRadiusProperty =
System.Windows.Controls.Border.CornerRadiusProperty.AddOwner(typeof(ListView));
/// <summary>
/// The DependencyProperty of <see cref="DisabledBackground"/> property
/// </summary>
public static readonly DependencyProperty DisabledBackgroundProperty =
DependencyProperty.Register(nameof(DisabledBackground), typeof(Brush), typeof(ListView), new FrameworkPropertyMetadata(null));
/// <summary>
/// The DependencyProperty of <see cref="DisabledBorderBrush"/> property
/// </summary>
public static readonly DependencyProperty DisabledBorderBrushProperty =
DependencyProperty.Register(nameof(DisabledBorderBrush), typeof(Brush), typeof(ListView), new FrameworkPropertyMetadata(null));
}
/// <summary>
/// The DependencyProperty of <see cref="DisabledBackground"/> property
/// </summary>
public static readonly DependencyProperty DisabledBackgroundProperty =
DependencyProperty.Register(nameof(DisabledBackground), typeof(Brush), typeof(ListView), new FrameworkPropertyMetadata(null));
/// <summary>
/// The DependencyProperty of <see cref="DisabledBorderBrush"/> property
/// </summary>
public static readonly DependencyProperty DisabledBorderBrushProperty =
DependencyProperty.Register(nameof(DisabledBorderBrush), typeof(Brush), typeof(ListView), new FrameworkPropertyMetadata(null));
}
}

16
EleCho.WpfSuite/Controls/ListViewResources.xaml

@ -23,19 +23,19 @@ @@ -23,19 +23,19 @@
<Setter.Value>
<ControlTemplate TargetType="{x:Type ws:ListView}">
<Border x:Name="Part_BD"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="{TemplateBinding CornerRadius}"
Padding="1"
SnapsToDevicePixels="true">
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="{TemplateBinding CornerRadius}"
Padding="1"
SnapsToDevicePixels="true">
<ws:ScrollViewer x:Name="PART_Content"
Focusable="false" Padding="{TemplateBinding Padding}">
<ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
</ws:ScrollViewer>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="False">
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter TargetName="Part_BD" Property="Background">
<Setter.Value>
<MultiBinding Converter="{x:Static ws:FallbackConverter.Instance}">

848
EleCho.WpfSuite/Controls/ScrollViewer.cs

@ -20,437 +20,427 @@ using System.Windows.Shapes; @@ -20,437 +20,427 @@ using System.Windows.Shapes;
namespace EleCho.WpfSuite
{
/// <inheritdoc/>
public class ScrollViewer : System.Windows.Controls.ScrollViewer
{
static ScrollViewer()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(ScrollViewer), new FrameworkPropertyMetadata(typeof(ScrollViewer)));
/// <inheritdoc/>
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<GetBool>();
_propertyHandlesMouseWheelScrollingGetter = typeof(ScrollViewer)
.GetProperty("HandlesMouseWheelScrolling", BindingFlags.Instance | BindingFlags.NonPublic)!
.GetGetMethod(true)!
.CreateDelegate<GetBool>();
#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;
/// <inheritdoc/>
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;
}
/// <inheritdoc/>
protected override void OnMouseWheel(MouseWheelEventArgs e)
{
if (!ScrollWithWheelDelta)
{
base.OnMouseWheel(e);
}
else
{
Debug.WriteLine(e.Delta);
CoreScrollWithWheelDelta(e);
}
}
/// <summary>
/// The horizontal offset of scrolling target
/// </summary>
public double HorizontalOffsetTarget
{
get { return (double)GetValue(HorizontalOffsetTargetProperty); }
}
/// <summary>
/// The vertical offset of scrolling target
/// </summary>
public double VerticalOffsetTarget
{
get { return (double)GetValue(VerticalOffsetTargetProperty); }
}
/// <summary>
/// Scroll with wheel delta instead of scrolling fixed number of lines
/// </summary>
public bool ScrollWithWheelDelta
{
get { return (bool)GetValue(ScrollWithWheelDeltaProperty); }
set { SetValue(ScrollWithWheelDeltaProperty, value); }
}
/// <summary>
/// Enable scrolling animation while using mouse <br/>
/// You need to set ScrollWithWheelDelta to true to use this
/// </summary>
public bool EnableScrollingAnimation
{
get { return (bool)GetValue(EnableScrollingAnimationProperty); }
set { SetValue(EnableScrollingAnimationProperty, value); }
}
/// <summary>
/// Scrolling animation duration
/// </summary>
public Duration ScrollingAnimationDuration
{
get { return (Duration)GetValue(ScrollingAnimationDurationProperty); }
set { SetValue(ScrollingAnimationDurationProperty, value); }
}
/// <summary>
/// Delta value factor while mouse scrolling
/// </summary>
public double MouseScrollDeltaFactor
{
get { return (double)GetValue(MouseScrollDeltaFactorProperty); }
set { SetValue(MouseScrollDeltaFactorProperty, value); }
}
/// <summary>
/// Delta value factor while touchpad scrolling
/// </summary>
public double TouchpadScrollDeltaFactor
{
get { return (double)GetValue(TouchpadScrollDeltaFactorProperty); }
set { SetValue(TouchpadScrollDeltaFactorProperty, value); }
}
/// <summary>
/// Always handle mouse wheel scrolling. <br />
/// (Especially in "TextBox")
/// </summary>
public bool AlwaysHandleMouseWheelScrolling
{
get { return (bool)GetValue(AlwaysHandleMouseWheelScrollingProperty); }
set { SetValue(AlwaysHandleMouseWheelScrollingProperty, value); }
}
/// <summary>
/// The key needed set a read-only property
/// </summary>
public static readonly DependencyPropertyKey HorizontalOffsetTargetPropertyKey =
DependencyProperty.RegisterReadOnly(nameof(HorizontalOffsetTarget), typeof(double), typeof(ScrollViewer), new PropertyMetadata(0.0));
/// <summary>
/// The key needed set a read-only property
/// </summary>
public static readonly DependencyPropertyKey VerticalOffsetTargetPropertyKey =
DependencyProperty.RegisterReadOnly(nameof(VerticalOffsetTarget), typeof(double), typeof(ScrollViewer), new PropertyMetadata(0.0));
/// <summary>
/// The key needed set a read-only property
/// </summary>
public static readonly DependencyProperty HorizontalOffsetTargetProperty =
HorizontalOffsetTargetPropertyKey.DependencyProperty;
/// <summary>
/// The key needed set a read-only property
/// </summary>
public static readonly DependencyProperty VerticalOffsetTargetProperty =
VerticalOffsetTargetPropertyKey.DependencyProperty;
/// <summary>
/// Get value of ScrollWithWheelDelta property
/// </summary>
/// <param name="obj"></param>
/// <returns></returns>
public static bool GetScrollWithWheelDelta(DependencyObject obj)
{
return (bool)obj.GetValue(ScrollWithWheelDeltaProperty);
}
/// <summary>
/// Set value of ScrollWithWheelDelta property
/// </summary>
/// <param name="obj"></param>
/// <param name="value"></param>
public static void SetScrollWithWheelDelta(DependencyObject obj, bool value)
{
obj.SetValue(ScrollWithWheelDeltaProperty, value);
}
/// <summary>
/// Get value of EnableScrollingAnimation property
/// </summary>
/// <param name="obj"></param>
/// <returns></returns>
public static bool GetEnableScrollingAnimation(DependencyObject obj)
{
return (bool)obj.GetValue(EnableScrollingAnimationProperty);
}
/// <summary>
/// Set value of EnableScrollingAnimation property
/// </summary>
/// <param name="obj"></param>
/// <param name="value"></param>
public static void SetEnableScrollingAnimation(DependencyObject obj, bool value)
{
obj.SetValue(EnableScrollingAnimationProperty, value);
}
/// <summary>
/// Get value of ScrollingAnimationDuration property
/// </summary>
/// <param name="obj"></param>
/// <returns></returns>
public static Duration GetScrollingAnimationDuration(DependencyObject obj)
{
return (Duration)obj.GetValue(ScrollingAnimationDurationProperty);
}
/// <summary>
/// Set value of ScrollingAnimationDuration property
/// </summary>
/// <param name="obj"></param>
/// <param name="value"></param>
public static void SetScrollingAnimationDuration(DependencyObject obj, Duration value)
{
obj.SetValue(ScrollingAnimationDurationProperty, value);
}
/// <summary>
/// Set value of AlwaysHandleMouseWheelScrolling property
/// </summary>
/// <param name="obj"></param>
/// <returns></returns>
public static bool GetAlwaysHandleMouseWheelScrolling(DependencyObject obj)
{
return (bool)obj.GetValue(AlwaysHandleMouseWheelScrollingProperty);
}
/// <summary>
/// Get value of AlwaysHandleMouseWheelScrolling property
/// </summary>
/// <param name="obj"></param>
/// <param name="value"></param>
public static void SetAlwaysHandleMouseWheelScrolling(DependencyObject obj, bool value)
{
obj.SetValue(AlwaysHandleMouseWheelScrollingProperty, value);
}
/// <summary>
/// The DependencyProperty of <see cref="ScrollWithWheelDelta"/> property.
/// </summary>
public static readonly DependencyProperty ScrollWithWheelDeltaProperty =
DependencyProperty.RegisterAttached(nameof(ScrollWithWheelDelta), typeof(bool), typeof(ScrollViewer),
new FrameworkPropertyMetadata(true, FrameworkPropertyMetadataOptions.Inherits));
/// <summary>
/// The DependencyProperty of <see cref="EnableScrollingAnimation"/> property.
/// </summary>
public static readonly DependencyProperty EnableScrollingAnimationProperty =
DependencyProperty.RegisterAttached(nameof(EnableScrollingAnimation), typeof(bool), typeof(ScrollViewer),
new FrameworkPropertyMetadata(true, FrameworkPropertyMetadataOptions.Inherits));
/// <summary>
/// The DependencyProperty of <see cref="ScrollingAnimationDuration"/> property.
/// </summary>
public static readonly DependencyProperty ScrollingAnimationDurationProperty =
DependencyProperty.RegisterAttached(nameof(ScrollingAnimationDuration), typeof(Duration), typeof(ScrollViewer),
new FrameworkPropertyMetadata(new Duration(TimeSpan.FromMilliseconds(250)), FrameworkPropertyMetadataOptions.Inherits), ValidateScrollingAnimationDuration);
/// <summary>
/// The DependencyProperty of <see cref="AlwaysHandleMouseWheelScrolling"/> property
/// </summary>
public static readonly DependencyProperty AlwaysHandleMouseWheelScrollingProperty =
DependencyProperty.RegisterAttached(nameof(AlwaysHandleMouseWheelScrolling), typeof(bool), typeof(ScrollViewer), new FrameworkPropertyMetadata(true, FrameworkPropertyMetadataOptions.Inherits));
/// <summary>
/// The DependencyProperty of <see cref="MouseScrollDeltaFactor"/> property
/// </summary>
public static readonly DependencyProperty MouseScrollDeltaFactorProperty =
DependencyProperty.Register(nameof(MouseScrollDeltaFactor), typeof(double), typeof(ScrollViewer), new PropertyMetadata(1.0));
/// <summary>
/// The DependencyProperty of <see cref="TouchpadScrollDeltaFactor"/> property
/// </summary>
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;
/// <inheritdoc/>
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;
}
/// <inheritdoc/>
protected override void OnMouseWheel(MouseWheelEventArgs e)
{
if (!ScrollWithWheelDelta)
{
base.OnMouseWheel(e);
}
else
{
Debug.WriteLine(e.Delta);
CoreScrollWithWheelDelta(e);
}
}
/// <summary>
/// The horizontal offset of scrolling target
/// </summary>
public double HorizontalOffsetTarget {
get { return (double)GetValue(HorizontalOffsetTargetProperty); }
}
/// <summary>
/// The vertical offset of scrolling target
/// </summary>
public double VerticalOffsetTarget {
get { return (double)GetValue(VerticalOffsetTargetProperty); }
}
/// <summary>
/// Scroll with wheel delta instead of scrolling fixed number of lines
/// </summary>
public bool ScrollWithWheelDelta {
get { return (bool)GetValue(ScrollWithWheelDeltaProperty); }
set { SetValue(ScrollWithWheelDeltaProperty, value); }
}
/// <summary>
/// Enable scrolling animation while using mouse <br/>
/// You need to set ScrollWithWheelDelta to true to use this
/// </summary>
public bool EnableScrollingAnimation {
get { return (bool)GetValue(EnableScrollingAnimationProperty); }
set { SetValue(EnableScrollingAnimationProperty, value); }
}
/// <summary>
/// Scrolling animation duration
/// </summary>
public Duration ScrollingAnimationDuration {
get { return (Duration)GetValue(ScrollingAnimationDurationProperty); }
set { SetValue(ScrollingAnimationDurationProperty, value); }
}
/// <summary>
/// Delta value factor while mouse scrolling
/// </summary>
public double MouseScrollDeltaFactor {
get { return (double)GetValue(MouseScrollDeltaFactorProperty); }
set { SetValue(MouseScrollDeltaFactorProperty, value); }
}
/// <summary>
/// Delta value factor while touchpad scrolling
/// </summary>
public double TouchpadScrollDeltaFactor {
get { return (double)GetValue(TouchpadScrollDeltaFactorProperty); }
set { SetValue(TouchpadScrollDeltaFactorProperty, value); }
}
/// <summary>
/// Always handle mouse wheel scrolling. <br />
/// (Especially in "TextBox")
/// </summary>
public bool AlwaysHandleMouseWheelScrolling {
get { return (bool)GetValue(AlwaysHandleMouseWheelScrollingProperty); }
set { SetValue(AlwaysHandleMouseWheelScrollingProperty, value); }
}
/// <summary>
/// The key needed set a read-only property
/// </summary>
public static readonly DependencyPropertyKey HorizontalOffsetTargetPropertyKey =
DependencyProperty.RegisterReadOnly(nameof(HorizontalOffsetTarget), typeof(double), typeof(ScrollViewer), new PropertyMetadata(0.0));
/// <summary>
/// The key needed set a read-only property
/// </summary>
public static readonly DependencyPropertyKey VerticalOffsetTargetPropertyKey =
DependencyProperty.RegisterReadOnly(nameof(VerticalOffsetTarget), typeof(double), typeof(ScrollViewer), new PropertyMetadata(0.0));
/// <summary>
/// The key needed set a read-only property
/// </summary>
public static readonly DependencyProperty HorizontalOffsetTargetProperty =
HorizontalOffsetTargetPropertyKey.DependencyProperty;
/// <summary>
/// The key needed set a read-only property
/// </summary>
public static readonly DependencyProperty VerticalOffsetTargetProperty =
VerticalOffsetTargetPropertyKey.DependencyProperty;
/// <summary>
/// Get value of ScrollWithWheelDelta property
/// </summary>
/// <param name="obj"></param>
/// <returns></returns>
public static bool GetScrollWithWheelDelta(DependencyObject obj)
{
return (bool)obj.GetValue(ScrollWithWheelDeltaProperty);
}
/// <summary>
/// Set value of ScrollWithWheelDelta property
/// </summary>
/// <param name="obj"></param>
/// <param name="value"></param>
public static void SetScrollWithWheelDelta(DependencyObject obj, bool value)
{
obj.SetValue(ScrollWithWheelDeltaProperty, value);
}
/// <summary>
/// Get value of EnableScrollingAnimation property
/// </summary>
/// <param name="obj"></param>
/// <returns></returns>
public static bool GetEnableScrollingAnimation(DependencyObject obj)
{
return (bool)obj.GetValue(EnableScrollingAnimationProperty);
}
/// <summary>
/// Set value of EnableScrollingAnimation property
/// </summary>
/// <param name="obj"></param>
/// <param name="value"></param>
public static void SetEnableScrollingAnimation(DependencyObject obj, bool value)
{
obj.SetValue(EnableScrollingAnimationProperty, value);
}
/// <summary>
/// Get value of ScrollingAnimationDuration property
/// </summary>
/// <param name="obj"></param>
/// <returns></returns>
public static Duration GetScrollingAnimationDuration(DependencyObject obj)
{
return (Duration)obj.GetValue(ScrollingAnimationDurationProperty);
}
/// <summary>
/// Set value of ScrollingAnimationDuration property
/// </summary>
/// <param name="obj"></param>
/// <param name="value"></param>
public static void SetScrollingAnimationDuration(DependencyObject obj, Duration value)
{
obj.SetValue(ScrollingAnimationDurationProperty, value);
}
/// <summary>
/// Set value of AlwaysHandleMouseWheelScrolling property
/// </summary>
/// <param name="obj"></param>
/// <returns></returns>
public static bool GetAlwaysHandleMouseWheelScrolling(DependencyObject obj)
{
return (bool)obj.GetValue(AlwaysHandleMouseWheelScrollingProperty);
}
/// <summary>
/// Get value of AlwaysHandleMouseWheelScrolling property
/// </summary>
/// <param name="obj"></param>
/// <param name="value"></param>
public static void SetAlwaysHandleMouseWheelScrolling(DependencyObject obj, bool value)
{
obj.SetValue(AlwaysHandleMouseWheelScrollingProperty, value);
}
/// <summary>
/// The DependencyProperty of <see cref="ScrollWithWheelDelta"/> property.
/// </summary>
public static readonly DependencyProperty ScrollWithWheelDeltaProperty =
DependencyProperty.RegisterAttached(nameof(ScrollWithWheelDelta), typeof(bool), typeof(ScrollViewer),
new FrameworkPropertyMetadata(true, FrameworkPropertyMetadataOptions.Inherits));
/// <summary>
/// The DependencyProperty of <see cref="EnableScrollingAnimation"/> property.
/// </summary>
public static readonly DependencyProperty EnableScrollingAnimationProperty =
DependencyProperty.RegisterAttached(nameof(EnableScrollingAnimation), typeof(bool), typeof(ScrollViewer),
new FrameworkPropertyMetadata(true, FrameworkPropertyMetadataOptions.Inherits));
/// <summary>
/// The DependencyProperty of <see cref="ScrollingAnimationDuration"/> property.
/// </summary>
public static readonly DependencyProperty ScrollingAnimationDurationProperty =
DependencyProperty.RegisterAttached(nameof(ScrollingAnimationDuration), typeof(Duration), typeof(ScrollViewer),
new FrameworkPropertyMetadata(new Duration(TimeSpan.FromMilliseconds(250)), FrameworkPropertyMetadataOptions.Inherits), ValidateScrollingAnimationDuration);
/// <summary>
/// The DependencyProperty of <see cref="AlwaysHandleMouseWheelScrolling"/> property
/// </summary>
public static readonly DependencyProperty AlwaysHandleMouseWheelScrollingProperty =
DependencyProperty.RegisterAttached(nameof(AlwaysHandleMouseWheelScrolling), typeof(bool), typeof(ScrollViewer), new FrameworkPropertyMetadata(true, FrameworkPropertyMetadataOptions.Inherits));
/// <summary>
/// The DependencyProperty of <see cref="MouseScrollDeltaFactor"/> property
/// </summary>
public static readonly DependencyProperty MouseScrollDeltaFactorProperty =
DependencyProperty.Register(nameof(MouseScrollDeltaFactor), typeof(double), typeof(ScrollViewer), new PropertyMetadata(1.0));
/// <summary>
/// The DependencyProperty of <see cref="TouchpadScrollDeltaFactor"/> property
/// </summary>
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;
}
}

102
EleCho.WpfSuite/MathHelper.cs

@ -8,68 +8,68 @@ using System.Windows; @@ -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;
}
}
}

8
EleCho.WpfSuite/Themes/Generic.xaml

@ -1,7 +1,7 @@ @@ -1,7 +1,7 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/EleCho.WpfSuite;component/Controls/ListBoxResources.xaml"/>
<ResourceDictionary Source="pack://application:,,,/EleCho.WpfSuite;component/Controls/ListViewResources.xaml"/>
</ResourceDictionary.MergedDictionaries>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/EleCho.WpfSuite;component/Controls/ListBoxResources.xaml"/>
<ResourceDictionary Source="pack://application:,,,/EleCho.WpfSuite;component/Controls/ListViewResources.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>

196
EleCho.WpfSuite/Utilities/ScrollViewerUtils.cs

@ -5,116 +5,116 @@ using System.Windows.Controls.Primitives; @@ -5,116 +5,116 @@ using System.Windows.Controls.Primitives;
namespace EleCho.WpfSuite
{
/// <summary>
/// ScrollViewer Utilities
/// </summary>
public static class ScrollViewerUtils
{
/// <summary>
/// Get value of VerticalOffset property
/// </summary>
/// <param name="d"></param>
/// <returns></returns>
public static double GetVerticalOffset(DependencyObject d)
{
if (d is ScrollViewer sv)
{
return sv.VerticalOffset;
}
else if (d is ScrollContentPresenter scp)
{
return scp.VerticalOffset;
}
/// <summary>
/// ScrollViewer Utilities
/// </summary>
public static class ScrollViewerUtils
{
/// <summary>
/// Get value of VerticalOffset property
/// </summary>
/// <param name="d"></param>
/// <returns></returns>
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);
}
/// <summary>
/// Set value of VerticalOffset property
/// </summary>
/// <param name="obj"></param>
/// <param name="value"></param>
public static void SetVerticalOffset(DependencyObject obj, double value)
{
obj.SetValue(VerticalOffsetProperty, value);
}
/// <summary>
/// Set value of VerticalOffset property
/// </summary>
/// <param name="obj"></param>
/// <param name="value"></param>
public static void SetVerticalOffset(DependencyObject obj, double value)
{
obj.SetValue(VerticalOffsetProperty, value);
}
/// <summary>
/// Get value of HorizontalOffset property
/// </summary>
/// <param name="d"></param>
/// <returns></returns>
public static double GetHorizontalOffset(DependencyObject d)
{
if (d is ScrollViewer sv)
{
return sv.HorizontalOffset;
}
else if (d is ScrollContentPresenter scp)
{
return scp.HorizontalOffset;
}
/// <summary>
/// Get value of HorizontalOffset property
/// </summary>
/// <param name="d"></param>
/// <returns></returns>
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);
}
/// <summary>
/// Set value of HorizontalOffset property
/// </summary>
/// <param name="obj"></param>
/// <param name="value"></param>
public static void SetHorizontalOffset(DependencyObject obj, double value)
{
obj.SetValue(HorizontalOffsetProperty, value);
}
/// <summary>
/// Set value of HorizontalOffset property
/// </summary>
/// <param name="obj"></param>
/// <param name="value"></param>
public static void SetHorizontalOffset(DependencyObject obj, double value)
{
obj.SetValue(HorizontalOffsetProperty, value);
}
/// <summary>
/// The DependencyProperty of VerticalOffset property
/// </summary>
public static readonly DependencyProperty VerticalOffsetProperty =
DependencyProperty.RegisterAttached("VerticalOffset", typeof(double), typeof(ScrollViewerUtils), new PropertyMetadata(0.0, VerticalOffsetChangedCallback));
/// <summary>
/// The DependencyProperty of VerticalOffset property
/// </summary>
public static readonly DependencyProperty VerticalOffsetProperty =
DependencyProperty.RegisterAttached("VerticalOffset", typeof(double), typeof(ScrollViewerUtils), new PropertyMetadata(0.0, VerticalOffsetChangedCallback));
/// <summary>
/// The DependencyProperty of HorizontalOffset property
/// </summary>
public static readonly DependencyProperty HorizontalOffsetProperty =
DependencyProperty.RegisterAttached("HorizontalOffset", typeof(double), typeof(ScrollViewerUtils), new PropertyMetadata(0.0, HorizontalOffsetChangedCallback));
/// <summary>
/// The DependencyProperty of HorizontalOffset property
/// </summary>
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);
}
}
}
}

34
EleCho.WpfSuite/ValueConverters/FallbackConverter.cs

@ -4,23 +4,23 @@ using System.Windows; @@ -4,23 +4,23 @@ using System.Windows;
namespace EleCho.WpfSuite
{
/// <summary>
/// Fallback between multiple values, return the first non-null value
/// </summary>
public class FallbackConverter : SingletonMultiValueConverterBase<FallbackConverter>
{
/// <inheritdoc/>
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;
}
/// <summary>
/// Fallback between multiple values, return the first non-null value
/// </summary>
public class FallbackConverter : SingletonMultiValueConverterBase<FallbackConverter>
{
/// <inheritdoc/>
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;
}
}
}

28
EleCho.WpfSuite/ValueConverters/MultiValueConverterBase.cs

@ -4,19 +4,19 @@ using System.Windows.Data; @@ -4,19 +4,19 @@ using System.Windows.Data;
namespace EleCho.WpfSuite
{
/// <summary>
/// Base class of multi value converter
/// </summary>
/// <typeparam name="TSelf"></typeparam>
public abstract class MultiValueConverterBase<TSelf> : IMultiValueConverter
{
/// <inheritdoc/>
public abstract object? Convert(object?[] values, Type targetType, object? parameter, CultureInfo culture);
/// <summary>
/// Base class of multi value converter
/// </summary>
/// <typeparam name="TSelf"></typeparam>
public abstract class MultiValueConverterBase<TSelf> : IMultiValueConverter
{
/// <inheritdoc/>
public abstract object? Convert(object?[] values, Type targetType, object? parameter, CultureInfo culture);
/// <inheritdoc/>
public virtual object?[] ConvertBack(object? value, Type[] targetTypes, object? parameter, CultureInfo culture)
{
throw new NotSupportedException();
}
}
/// <inheritdoc/>
public virtual object?[] ConvertBack(object? value, Type[] targetTypes, object? parameter, CultureInfo culture)
{
throw new NotSupportedException();
}
}
}

26
EleCho.WpfSuite/ValueConverters/SingletonMultiValueConverterBase.cs

@ -1,17 +1,17 @@ @@ -1,17 +1,17 @@
namespace EleCho.WpfSuite
{
/// <summary>
/// Base class of singleton multi value converter
/// </summary>
/// <typeparam name="TSelf"></typeparam>
public abstract class SingletonMultiValueConverterBase<TSelf> : MultiValueConverterBase<TSelf>
where TSelf : SingletonMultiValueConverterBase<TSelf>, new()
{
private static TSelf? _instance = null;
/// <summary>
/// Base class of singleton multi value converter
/// </summary>
/// <typeparam name="TSelf"></typeparam>
public abstract class SingletonMultiValueConverterBase<TSelf> : MultiValueConverterBase<TSelf>
where TSelf : SingletonMultiValueConverterBase<TSelf>, new()
{
private static TSelf? _instance = null;
/// <summary>
/// Get an instance of <typeparamref name="TSelf"/>
/// </summary>
public static TSelf Instance => _instance ?? new();
}
/// <summary>
/// Get an instance of <typeparamref name="TSelf"/>
/// </summary>
public static TSelf Instance => _instance ?? new();
}
}

Loading…
Cancel
Save