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;
namespace EleCho.WpfSuite namespace EleCho.WpfSuite
{ {
/// <inheritdoc/> /// <inheritdoc/>
public class ListBox : System.Windows.Controls.ListBox public class ListBox : System.Windows.Controls.ListBox
{ {
static ListBox() static ListBox()
{ {
DefaultStyleKeyProperty.OverrideMetadata(typeof(ListBox), new FrameworkPropertyMetadata(typeof(ListBox))); DefaultStyleKeyProperty.OverrideMetadata(typeof(ListBox), new FrameworkPropertyMetadata(typeof(ListBox)));
} }
/// <summary> /// <summary>
/// The CornerRadius property allows users to control the roundness of the corners independently by /// 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 /// setting a radius value for each corner. Radius values that are too large are scaled so that they
/// smoothly blend from corner to corner. /// smoothly blend from corner to corner.
/// </summary> /// </summary>
public CornerRadius CornerRadius public CornerRadius CornerRadius {
{ get { return (CornerRadius)GetValue(CornerRadiusProperty); }
get { return (CornerRadius)GetValue(CornerRadiusProperty); } set { SetValue(CornerRadiusProperty, value); }
set { SetValue(CornerRadiusProperty, value); } }
}
/// <summary> /// <summary>
/// Background when disabled /// Background when disabled
/// </summary> /// </summary>
public Brush DisabledBackground public Brush DisabledBackground {
{ get { return (Brush)GetValue(DisabledBackgroundProperty); }
get { return (Brush)GetValue(DisabledBackgroundProperty); } set { SetValue(DisabledBackgroundProperty, value); }
set { SetValue(DisabledBackgroundProperty, value); } }
}
/// <summary> /// <summary>
/// BorderBrush when pressed by mouse /// BorderBrush when pressed by mouse
/// </summary> /// </summary>
public Brush DisabledBorderBrush public Brush DisabledBorderBrush {
{ get { return (Brush)GetValue(DisabledBorderBrushProperty); }
get { return (Brush)GetValue(DisabledBorderBrushProperty); } set { SetValue(DisabledBorderBrushProperty, value); }
set { SetValue(DisabledBorderBrushProperty, value); } }
}
/// <summary> /// <summary>
/// DependencyProperty of <see cref="CornerRadius"/> property /// DependencyProperty of <see cref="CornerRadius"/> property
/// </summary> /// </summary>
public static readonly DependencyProperty CornerRadiusProperty = public static readonly DependencyProperty CornerRadiusProperty =
System.Windows.Controls.Border.CornerRadiusProperty.AddOwner(typeof(ListBox)); System.Windows.Controls.Border.CornerRadiusProperty.AddOwner(typeof(ListBox));
/// <summary> /// <summary>
/// The DependencyProperty of <see cref="DisabledBackground"/> property /// The DependencyProperty of <see cref="DisabledBackground"/> property
/// </summary> /// </summary>
public static readonly DependencyProperty DisabledBackgroundProperty = public static readonly DependencyProperty DisabledBackgroundProperty =
DependencyProperty.Register(nameof(DisabledBackground), typeof(Brush), typeof(ListBox), new FrameworkPropertyMetadata(null)); DependencyProperty.Register(nameof(DisabledBackground), typeof(Brush), typeof(ListBox), new FrameworkPropertyMetadata(null));
/// <summary> /// <summary>
/// The DependencyProperty of <see cref="DisabledBorderBrush"/> property /// The DependencyProperty of <see cref="DisabledBorderBrush"/> property
/// </summary> /// </summary>
public static readonly DependencyProperty DisabledBorderBrushProperty = public static readonly DependencyProperty DisabledBorderBrushProperty =
DependencyProperty.Register(nameof(DisabledBorderBrush), typeof(Brush), typeof(ListBox), new FrameworkPropertyMetadata(null)); DependencyProperty.Register(nameof(DisabledBorderBrush), typeof(Brush), typeof(ListBox), new FrameworkPropertyMetadata(null));
} }
} }

16
EleCho.WpfSuite/Controls/ListBoxResources.xaml

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

107
EleCho.WpfSuite/Controls/ListView.cs

@ -3,61 +3,58 @@ using System.Windows.Media;
namespace EleCho.WpfSuite namespace EleCho.WpfSuite
{ {
/// <inheritdoc/> /// <inheritdoc/>
public class ListView : System.Windows.Controls.ListView public class ListView : System.Windows.Controls.ListView
{ {
static ListView() static ListView()
{ {
DefaultStyleKeyProperty.OverrideMetadata(typeof(ListView), new FrameworkPropertyMetadata(typeof(ListView))); DefaultStyleKeyProperty.OverrideMetadata(typeof(ListView), new FrameworkPropertyMetadata(typeof(ListView)));
} }
/// <summary> /// <summary>
/// The CornerRadius property allows users to control the roundness of the corners independently by /// 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 /// setting a radius value for each corner. Radius values that are too large are scaled so that they
/// smoothly blend from corner to corner. /// smoothly blend from corner to corner.
/// </summary> /// </summary>
public CornerRadius CornerRadius public CornerRadius CornerRadius {
{ get { return (CornerRadius)GetValue(CornerRadiusProperty); }
get { return (CornerRadius)GetValue(CornerRadiusProperty); } set { SetValue(CornerRadiusProperty, value); }
set { SetValue(CornerRadiusProperty, value); } }
}
/// <summary>
/// <summary> /// Background when disabled
/// Background when disabled /// </summary>
/// </summary> public Brush DisabledBackground {
public Brush DisabledBackground get { return (Brush)GetValue(DisabledBackgroundProperty); }
{ set { SetValue(DisabledBackgroundProperty, value); }
get { return (Brush)GetValue(DisabledBackgroundProperty); } }
set { SetValue(DisabledBackgroundProperty, value); }
} /// <summary>
/// BorderBrush when pressed by mouse
/// <summary> /// </summary>
/// BorderBrush when pressed by mouse public Brush DisabledBorderBrush {
/// </summary> get { return (Brush)GetValue(DisabledBorderBrushProperty); }
public Brush DisabledBorderBrush set { SetValue(DisabledBorderBrushProperty, value); }
{ }
get { return (Brush)GetValue(DisabledBorderBrushProperty); }
set { SetValue(DisabledBorderBrushProperty, value); }
} /// <summary>
/// DependencyProperty of <see cref="CornerRadius"/> property
/// </summary>
/// <summary> public static readonly DependencyProperty CornerRadiusProperty =
/// DependencyProperty of <see cref="CornerRadius"/> property
/// </summary>
public static readonly DependencyProperty CornerRadiusProperty =
System.Windows.Controls.Border.CornerRadiusProperty.AddOwner(typeof(ListView)); System.Windows.Controls.Border.CornerRadiusProperty.AddOwner(typeof(ListView));
/// <summary> /// <summary>
/// The DependencyProperty of <see cref="DisabledBackground"/> property /// The DependencyProperty of <see cref="DisabledBackground"/> property
/// </summary> /// </summary>
public static readonly DependencyProperty DisabledBackgroundProperty = public static readonly DependencyProperty DisabledBackgroundProperty =
DependencyProperty.Register(nameof(DisabledBackground), typeof(Brush), typeof(ListView), new FrameworkPropertyMetadata(null)); DependencyProperty.Register(nameof(DisabledBackground), typeof(Brush), typeof(ListView), new FrameworkPropertyMetadata(null));
/// <summary> /// <summary>
/// The DependencyProperty of <see cref="DisabledBorderBrush"/> property /// The DependencyProperty of <see cref="DisabledBorderBrush"/> property
/// </summary> /// </summary>
public static readonly DependencyProperty DisabledBorderBrushProperty = public static readonly DependencyProperty DisabledBorderBrushProperty =
DependencyProperty.Register(nameof(DisabledBorderBrush), typeof(Brush), typeof(ListView), new FrameworkPropertyMetadata(null)); DependencyProperty.Register(nameof(DisabledBorderBrush), typeof(Brush), typeof(ListView), new FrameworkPropertyMetadata(null));
} }
} }

16
EleCho.WpfSuite/Controls/ListViewResources.xaml

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

848
EleCho.WpfSuite/Controls/ScrollViewer.cs

@ -20,437 +20,427 @@ using System.Windows.Shapes;
namespace EleCho.WpfSuite namespace EleCho.WpfSuite
{ {
/// <inheritdoc/> /// <inheritdoc/>
public class ScrollViewer : System.Windows.Controls.ScrollViewer public class ScrollViewer : System.Windows.Controls.ScrollViewer
{ {
static ScrollViewer() static ScrollViewer()
{ {
DefaultStyleKeyProperty.OverrideMetadata(typeof(ScrollViewer), new FrameworkPropertyMetadata(typeof(ScrollViewer))); DefaultStyleKeyProperty.OverrideMetadata(typeof(ScrollViewer), new FrameworkPropertyMetadata(typeof(ScrollViewer)));
#if NETCOREAPP #if NETCOREAPP
_propertyHandlesMouseWheelScrollingGetter = typeof(ScrollViewer) _propertyHandlesMouseWheelScrollingGetter = typeof(ScrollViewer)
.GetProperty("HandlesMouseWheelScrolling", BindingFlags.Instance | BindingFlags.NonPublic)! .GetProperty("HandlesMouseWheelScrolling", BindingFlags.Instance | BindingFlags.NonPublic)!
.GetGetMethod(true)! .GetGetMethod(true)!
.CreateDelegate<GetBool>(); .CreateDelegate<GetBool>();
#else #else
_propertyHandlesMouseWheelScrollingGetter = (GetBool)typeof(ScrollViewer) _propertyHandlesMouseWheelScrollingGetter = (GetBool)typeof(ScrollViewer)
.GetProperty("HandlesMouseWheelScrolling", BindingFlags.Instance | BindingFlags.NonPublic)! .GetProperty("HandlesMouseWheelScrolling", BindingFlags.Instance | BindingFlags.NonPublic)!
.GetGetMethod(true)! .GetGetMethod(true)!
.CreateDelegate(typeof(GetBool)); .CreateDelegate(typeof(GetBool));
#endif #endif
} }
private delegate bool GetBool(ScrollViewer scrollViewer); private delegate bool GetBool(ScrollViewer scrollViewer);
private static readonly GetBool _propertyHandlesMouseWheelScrollingGetter; private static readonly GetBool _propertyHandlesMouseWheelScrollingGetter;
private static readonly IEasingFunction _scrollingAnimationEase = new CubicEase(){ EasingMode = EasingMode.EaseOut }; private static readonly IEasingFunction _scrollingAnimationEase = new CubicEase() { EasingMode = EasingMode.EaseOut };
private const long _millisecondsBetweenTouchpadScrolling = 100; private const long _millisecondsBetweenTouchpadScrolling = 100;
private bool _animationRunning = false; private bool _animationRunning = false;
private int _lastScrollDelta = 0; private int _lastScrollDelta = 0;
private int _lastVerticalScrollingDelta = 0; private int _lastVerticalScrollingDelta = 0;
private int _lastHorizontalScrollingDelta = 0; private int _lastHorizontalScrollingDelta = 0;
private long _lastScrollingTick; private long _lastScrollingTick;
private FrameworkElement? _scrollContentPresenter; private FrameworkElement? _scrollContentPresenter;
/// <inheritdoc/> /// <inheritdoc/>
public override void OnApplyTemplate() public override void OnApplyTemplate()
{ {
base.OnApplyTemplate(); base.OnApplyTemplate();
_scrollContentPresenter = GetTemplateChild("PART_ScrollContentPresenter") as FrameworkElement; _scrollContentPresenter = GetTemplateChild("PART_ScrollContentPresenter") as FrameworkElement;
} }
private void CoreScrollWithWheelDelta(MouseWheelEventArgs e) private void CoreScrollWithWheelDelta(MouseWheelEventArgs e)
{ {
if (e.Handled) if (e.Handled)
{ {
return; return;
} }
if (!AlwaysHandleMouseWheelScrolling && if (!AlwaysHandleMouseWheelScrolling &&
!_propertyHandlesMouseWheelScrollingGetter.Invoke(this)) !_propertyHandlesMouseWheelScrollingGetter.Invoke(this))
{ {
return; return;
} }
bool vertical = ExtentHeight > 0; bool vertical = ExtentHeight > 0;
bool horizontal = ExtentWidth > 0; bool horizontal = ExtentWidth > 0;
var tickCount = Environment.TickCount; var tickCount = Environment.TickCount;
var isTouchpadScrolling = var isTouchpadScrolling =
e.Delta % Mouse.MouseWheelDeltaForOneLine != 0 || e.Delta % Mouse.MouseWheelDeltaForOneLine != 0 ||
(tickCount - _lastScrollingTick < _millisecondsBetweenTouchpadScrolling && _lastScrollDelta % Mouse.MouseWheelDeltaForOneLine != 0); (tickCount - _lastScrollingTick < _millisecondsBetweenTouchpadScrolling && _lastScrollDelta % Mouse.MouseWheelDeltaForOneLine != 0);
double scrollDelta = e.Delta; double scrollDelta = e.Delta;
if (isTouchpadScrolling) if (isTouchpadScrolling)
{ {
// touchpad 应该滚动更慢一些, 所以这里预先除以一个合适的值 // touchpad 应该滚动更慢一些, 所以这里预先除以一个合适的值
scrollDelta /= 2; scrollDelta /= 2;
// //
scrollDelta *= TouchpadScrollDeltaFactor; scrollDelta *= TouchpadScrollDeltaFactor;
} }
else else
{ {
scrollDelta *= MouseScrollDeltaFactor; scrollDelta *= MouseScrollDeltaFactor;
} }
if (vertical) if (vertical)
{ {
if (ScrollInfo is IScrollInfo scrollInfo) if (ScrollInfo is IScrollInfo scrollInfo)
{ {
// 考虑到 VirtualizingPanel 可能是虚拟的大小, 所以这里需要校正 Delta // 考虑到 VirtualizingPanel 可能是虚拟的大小, 所以这里需要校正 Delta
scrollDelta *= scrollInfo.ViewportHeight / (_scrollContentPresenter?.ActualHeight ?? ActualHeight); scrollDelta *= scrollInfo.ViewportHeight / (_scrollContentPresenter?.ActualHeight ?? ActualHeight);
} }
var sameDirectionAsLast = Math.Sign(e.Delta) == Math.Sign(_lastVerticalScrollingDelta); var sameDirectionAsLast = Math.Sign(e.Delta) == Math.Sign(_lastVerticalScrollingDelta);
var nowOffset = sameDirectionAsLast && _animationRunning ? VerticalOffsetTarget : VerticalOffset; var nowOffset = sameDirectionAsLast && _animationRunning ? VerticalOffsetTarget : VerticalOffset;
var newOffset = nowOffset - scrollDelta; var newOffset = nowOffset - scrollDelta;
if (newOffset < 0) if (newOffset < 0)
newOffset = 0; newOffset = 0;
if (newOffset > ScrollableHeight) if (newOffset > ScrollableHeight)
newOffset = ScrollableHeight; newOffset = ScrollableHeight;
SetValue(VerticalOffsetTargetPropertyKey, newOffset); SetValue(VerticalOffsetTargetPropertyKey, newOffset);
BeginAnimation(ScrollViewerUtils.VerticalOffsetProperty, null); BeginAnimation(ScrollViewerUtils.VerticalOffsetProperty, null);
if (!EnableScrollingAnimation || isTouchpadScrolling) if (!EnableScrollingAnimation || isTouchpadScrolling)
{ {
ScrollToVerticalOffset(newOffset); ScrollToVerticalOffset(newOffset);
} }
else else
{ {
var diff = newOffset - VerticalOffset; var diff = newOffset - VerticalOffset;
var absDiff = Math.Abs(diff); var absDiff = Math.Abs(diff);
var duration = ScrollingAnimationDuration; var duration = ScrollingAnimationDuration;
if (absDiff < Mouse.MouseWheelDeltaForOneLine) if (absDiff < Mouse.MouseWheelDeltaForOneLine)
{ {
duration = new Duration(TimeSpan.FromTicks((long)(duration.TimeSpan.Ticks * absDiff / Mouse.MouseWheelDeltaForOneLine))); duration = new Duration(TimeSpan.FromTicks((long)(duration.TimeSpan.Ticks * absDiff / Mouse.MouseWheelDeltaForOneLine)));
} }
DoubleAnimation doubleAnimation = new DoubleAnimation() DoubleAnimation doubleAnimation = new DoubleAnimation() {
{ EasingFunction = _scrollingAnimationEase,
EasingFunction = _scrollingAnimationEase, Duration = duration,
Duration = duration, From = VerticalOffset,
From = VerticalOffset, To = newOffset,
To = newOffset, };
};
doubleAnimation.Completed += DoubleAnimation_Completed;
doubleAnimation.Completed += DoubleAnimation_Completed;
_animationRunning = true;
_animationRunning = true; BeginAnimation(ScrollViewerUtils.VerticalOffsetProperty, doubleAnimation, HandoffBehavior.SnapshotAndReplace);
BeginAnimation(ScrollViewerUtils.VerticalOffsetProperty, doubleAnimation, HandoffBehavior.SnapshotAndReplace); }
}
_lastVerticalScrollingDelta = e.Delta;
_lastVerticalScrollingDelta = e.Delta; }
} else if (horizontal)
else if (horizontal) {
{ if (ScrollInfo is IScrollInfo scrollInfo)
if (ScrollInfo is IScrollInfo scrollInfo) {
{ // 考虑到 VirtualizingPanel 可能是虚拟的大小, 所以这里需要校正 Delta
// 考虑到 VirtualizingPanel 可能是虚拟的大小, 所以这里需要校正 Delta scrollDelta *= scrollInfo.ViewportWidth / (_scrollContentPresenter?.ActualWidth ?? ActualWidth);
scrollDelta *= scrollInfo.ViewportWidth / (_scrollContentPresenter?.ActualWidth ?? ActualWidth); }
}
var sameDirectionAsLast = Math.Sign(e.Delta) == Math.Sign(_lastHorizontalScrollingDelta);
var sameDirectionAsLast = Math.Sign(e.Delta) == Math.Sign(_lastHorizontalScrollingDelta); var nowOffset = sameDirectionAsLast && _animationRunning ? HorizontalOffsetTarget : HorizontalOffset;
var nowOffset = sameDirectionAsLast && _animationRunning ? HorizontalOffsetTarget : HorizontalOffset; var newOffset = nowOffset - scrollDelta;
var newOffset = nowOffset - scrollDelta;
if (newOffset < 0)
if (newOffset < 0) newOffset = 0;
newOffset = 0; if (newOffset > ScrollableWidth)
if (newOffset > ScrollableWidth) newOffset = ScrollableWidth;
newOffset = ScrollableWidth;
SetValue(HorizontalOffsetTargetPropertyKey, newOffset);
SetValue(HorizontalOffsetTargetPropertyKey, newOffset); BeginAnimation(ScrollViewerUtils.HorizontalOffsetProperty, null);
BeginAnimation(ScrollViewerUtils.HorizontalOffsetProperty, null);
if (!EnableScrollingAnimation || isTouchpadScrolling)
if (!EnableScrollingAnimation || isTouchpadScrolling) {
{ ScrollToHorizontalOffset(newOffset);
ScrollToHorizontalOffset(newOffset); }
} else
else {
{ var diff = newOffset - HorizontalOffset;
var diff = newOffset - HorizontalOffset; var absDiff = Math.Abs(diff);
var absDiff = Math.Abs(diff); var duration = ScrollingAnimationDuration;
var duration = ScrollingAnimationDuration; if (absDiff < Mouse.MouseWheelDeltaForOneLine)
if (absDiff < Mouse.MouseWheelDeltaForOneLine) {
{ duration = new Duration(TimeSpan.FromTicks((long)(duration.TimeSpan.Ticks * absDiff / Mouse.MouseWheelDeltaForOneLine)));
duration = new Duration(TimeSpan.FromTicks((long)(duration.TimeSpan.Ticks * absDiff / Mouse.MouseWheelDeltaForOneLine))); }
}
DoubleAnimation doubleAnimation = new DoubleAnimation() {
DoubleAnimation doubleAnimation = new DoubleAnimation() EasingFunction = _scrollingAnimationEase,
{ Duration = duration,
EasingFunction = _scrollingAnimationEase, From = HorizontalOffset,
Duration = duration, To = newOffset,
From = HorizontalOffset, };
To = newOffset,
}; doubleAnimation.Completed += DoubleAnimation_Completed;
doubleAnimation.Completed += DoubleAnimation_Completed; _animationRunning = true;
BeginAnimation(ScrollViewerUtils.HorizontalOffsetProperty, doubleAnimation, HandoffBehavior.SnapshotAndReplace);
_animationRunning = true; }
BeginAnimation(ScrollViewerUtils.HorizontalOffsetProperty, doubleAnimation, HandoffBehavior.SnapshotAndReplace);
} _lastHorizontalScrollingDelta = e.Delta;
}
_lastHorizontalScrollingDelta = e.Delta;
} _lastScrollingTick = tickCount;
_lastScrollDelta = e.Delta;
_lastScrollingTick = tickCount;
_lastScrollDelta = e.Delta; e.Handled = true;
}
e.Handled = true;
} private void DoubleAnimation_Completed(object? sender, EventArgs e)
{
private void DoubleAnimation_Completed(object? sender, EventArgs e) _animationRunning = false;
{ }
_animationRunning = false;
} /// <inheritdoc/>
protected override void OnMouseWheel(MouseWheelEventArgs e)
/// <inheritdoc/> {
protected override void OnMouseWheel(MouseWheelEventArgs e) if (!ScrollWithWheelDelta)
{ {
if (!ScrollWithWheelDelta) base.OnMouseWheel(e);
{ }
base.OnMouseWheel(e); else
} {
else Debug.WriteLine(e.Delta);
{
Debug.WriteLine(e.Delta); CoreScrollWithWheelDelta(e);
}
CoreScrollWithWheelDelta(e); }
}
} /// <summary>
/// The horizontal offset of scrolling target
/// <summary> /// </summary>
/// The horizontal offset of scrolling target public double HorizontalOffsetTarget {
/// </summary> get { return (double)GetValue(HorizontalOffsetTargetProperty); }
public double HorizontalOffsetTarget }
{
get { return (double)GetValue(HorizontalOffsetTargetProperty); } /// <summary>
} /// The vertical offset of scrolling target
/// </summary>
/// <summary> public double VerticalOffsetTarget {
/// The vertical offset of scrolling target get { return (double)GetValue(VerticalOffsetTargetProperty); }
/// </summary> }
public double VerticalOffsetTarget
{ /// <summary>
get { return (double)GetValue(VerticalOffsetTargetProperty); } /// Scroll with wheel delta instead of scrolling fixed number of lines
} /// </summary>
public bool ScrollWithWheelDelta {
/// <summary> get { return (bool)GetValue(ScrollWithWheelDeltaProperty); }
/// Scroll with wheel delta instead of scrolling fixed number of lines set { SetValue(ScrollWithWheelDeltaProperty, value); }
/// </summary> }
public bool ScrollWithWheelDelta
{ /// <summary>
get { return (bool)GetValue(ScrollWithWheelDeltaProperty); } /// Enable scrolling animation while using mouse <br/>
set { SetValue(ScrollWithWheelDeltaProperty, value); } /// You need to set ScrollWithWheelDelta to true to use this
} /// </summary>
public bool EnableScrollingAnimation {
/// <summary> get { return (bool)GetValue(EnableScrollingAnimationProperty); }
/// Enable scrolling animation while using mouse <br/> set { SetValue(EnableScrollingAnimationProperty, value); }
/// You need to set ScrollWithWheelDelta to true to use this }
/// </summary>
public bool EnableScrollingAnimation /// <summary>
{ /// Scrolling animation duration
get { return (bool)GetValue(EnableScrollingAnimationProperty); } /// </summary>
set { SetValue(EnableScrollingAnimationProperty, value); } public Duration ScrollingAnimationDuration {
} get { return (Duration)GetValue(ScrollingAnimationDurationProperty); }
set { SetValue(ScrollingAnimationDurationProperty, value); }
/// <summary> }
/// Scrolling animation duration
/// </summary> /// <summary>
public Duration ScrollingAnimationDuration /// Delta value factor while mouse scrolling
{ /// </summary>
get { return (Duration)GetValue(ScrollingAnimationDurationProperty); } public double MouseScrollDeltaFactor {
set { SetValue(ScrollingAnimationDurationProperty, value); } get { return (double)GetValue(MouseScrollDeltaFactorProperty); }
} set { SetValue(MouseScrollDeltaFactorProperty, value); }
}
/// <summary>
/// Delta value factor while mouse scrolling /// <summary>
/// </summary> /// Delta value factor while touchpad scrolling
public double MouseScrollDeltaFactor /// </summary>
{ public double TouchpadScrollDeltaFactor {
get { return (double)GetValue(MouseScrollDeltaFactorProperty); } get { return (double)GetValue(TouchpadScrollDeltaFactorProperty); }
set { SetValue(MouseScrollDeltaFactorProperty, value); } set { SetValue(TouchpadScrollDeltaFactorProperty, value); }
} }
/// <summary> /// <summary>
/// Delta value factor while touchpad scrolling /// Always handle mouse wheel scrolling. <br />
/// </summary> /// (Especially in "TextBox")
public double TouchpadScrollDeltaFactor /// </summary>
{ public bool AlwaysHandleMouseWheelScrolling {
get { return (double)GetValue(TouchpadScrollDeltaFactorProperty); } get { return (bool)GetValue(AlwaysHandleMouseWheelScrollingProperty); }
set { SetValue(TouchpadScrollDeltaFactorProperty, value); } set { SetValue(AlwaysHandleMouseWheelScrollingProperty, 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 =
/// <summary> DependencyProperty.RegisterReadOnly(nameof(VerticalOffsetTarget), typeof(double), typeof(ScrollViewer), new PropertyMetadata(0.0));
/// The key needed set a read-only property
/// </summary> /// <summary>
public static readonly DependencyPropertyKey HorizontalOffsetTargetPropertyKey = /// The key needed set a read-only property
DependencyProperty.RegisterReadOnly(nameof(HorizontalOffsetTarget), typeof(double), typeof(ScrollViewer), new PropertyMetadata(0.0)); /// </summary>
public static readonly DependencyProperty HorizontalOffsetTargetProperty =
/// <summary> HorizontalOffsetTargetPropertyKey.DependencyProperty;
/// The key needed set a read-only property
/// </summary> /// <summary>
public static readonly DependencyPropertyKey VerticalOffsetTargetPropertyKey = /// The key needed set a read-only property
DependencyProperty.RegisterReadOnly(nameof(VerticalOffsetTarget), typeof(double), typeof(ScrollViewer), new PropertyMetadata(0.0)); /// </summary>
public static readonly DependencyProperty VerticalOffsetTargetProperty =
/// <summary> VerticalOffsetTargetPropertyKey.DependencyProperty;
/// The key needed set a read-only property
/// </summary>
public static readonly DependencyProperty HorizontalOffsetTargetProperty =
HorizontalOffsetTargetPropertyKey.DependencyProperty; /// <summary>
/// Get value of ScrollWithWheelDelta property
/// <summary> /// </summary>
/// The key needed set a read-only property /// <param name="obj"></param>
/// </summary> /// <returns></returns>
public static readonly DependencyProperty VerticalOffsetTargetProperty = public static bool GetScrollWithWheelDelta(DependencyObject obj)
VerticalOffsetTargetPropertyKey.DependencyProperty; {
return (bool)obj.GetValue(ScrollWithWheelDeltaProperty);
}
/// <summary> /// <summary>
/// Get value of ScrollWithWheelDelta property /// Set value of ScrollWithWheelDelta property
/// </summary> /// </summary>
/// <param name="obj"></param> /// <param name="obj"></param>
/// <returns></returns> /// <param name="value"></param>
public static bool GetScrollWithWheelDelta(DependencyObject obj) public static void SetScrollWithWheelDelta(DependencyObject obj, bool value)
{ {
return (bool)obj.GetValue(ScrollWithWheelDeltaProperty); obj.SetValue(ScrollWithWheelDeltaProperty, value);
} }
/// <summary> /// <summary>
/// Set value of ScrollWithWheelDelta property /// Get value of EnableScrollingAnimation property
/// </summary> /// </summary>
/// <param name="obj"></param> /// <param name="obj"></param>
/// <param name="value"></param> /// <returns></returns>
public static void SetScrollWithWheelDelta(DependencyObject obj, bool value) public static bool GetEnableScrollingAnimation(DependencyObject obj)
{ {
obj.SetValue(ScrollWithWheelDeltaProperty, value); return (bool)obj.GetValue(EnableScrollingAnimationProperty);
} }
/// <summary> /// <summary>
/// Get value of EnableScrollingAnimation property /// Set value of EnableScrollingAnimation property
/// </summary> /// </summary>
/// <param name="obj"></param> /// <param name="obj"></param>
/// <returns></returns> /// <param name="value"></param>
public static bool GetEnableScrollingAnimation(DependencyObject obj) public static void SetEnableScrollingAnimation(DependencyObject obj, bool value)
{ {
return (bool)obj.GetValue(EnableScrollingAnimationProperty); obj.SetValue(EnableScrollingAnimationProperty, value);
} }
/// <summary> /// <summary>
/// Set value of EnableScrollingAnimation property /// Get value of ScrollingAnimationDuration property
/// </summary> /// </summary>
/// <param name="obj"></param> /// <param name="obj"></param>
/// <param name="value"></param> /// <returns></returns>
public static void SetEnableScrollingAnimation(DependencyObject obj, bool value) public static Duration GetScrollingAnimationDuration(DependencyObject obj)
{ {
obj.SetValue(EnableScrollingAnimationProperty, value); return (Duration)obj.GetValue(ScrollingAnimationDurationProperty);
} }
/// <summary> /// <summary>
/// Get value of ScrollingAnimationDuration property /// Set value of ScrollingAnimationDuration property
/// </summary> /// </summary>
/// <param name="obj"></param> /// <param name="obj"></param>
/// <returns></returns> /// <param name="value"></param>
public static Duration GetScrollingAnimationDuration(DependencyObject obj) public static void SetScrollingAnimationDuration(DependencyObject obj, Duration value)
{ {
return (Duration)obj.GetValue(ScrollingAnimationDurationProperty); obj.SetValue(ScrollingAnimationDurationProperty, value);
} }
/// <summary>
/// Set value of ScrollingAnimationDuration property /// <summary>
/// </summary> /// Set value of AlwaysHandleMouseWheelScrolling property
/// <param name="obj"></param> /// </summary>
/// <param name="value"></param> /// <param name="obj"></param>
public static void SetScrollingAnimationDuration(DependencyObject obj, Duration value) /// <returns></returns>
{ public static bool GetAlwaysHandleMouseWheelScrolling(DependencyObject obj)
obj.SetValue(ScrollingAnimationDurationProperty, value); {
} return (bool)obj.GetValue(AlwaysHandleMouseWheelScrollingProperty);
}
/// <summary> /// <summary>
/// Set value of AlwaysHandleMouseWheelScrolling property /// Get value of AlwaysHandleMouseWheelScrolling property
/// </summary> /// </summary>
/// <param name="obj"></param> /// <param name="obj"></param>
/// <returns></returns> /// <param name="value"></param>
public static bool GetAlwaysHandleMouseWheelScrolling(DependencyObject obj) public static void SetAlwaysHandleMouseWheelScrolling(DependencyObject obj, bool value)
{ {
return (bool)obj.GetValue(AlwaysHandleMouseWheelScrollingProperty); obj.SetValue(AlwaysHandleMouseWheelScrollingProperty, value);
} }
/// <summary>
/// Get value of AlwaysHandleMouseWheelScrolling property /// <summary>
/// </summary> /// The DependencyProperty of <see cref="ScrollWithWheelDelta"/> property.
/// <param name="obj"></param> /// </summary>
/// <param name="value"></param> public static readonly DependencyProperty ScrollWithWheelDeltaProperty =
public static void SetAlwaysHandleMouseWheelScrolling(DependencyObject obj, bool value) DependencyProperty.RegisterAttached(nameof(ScrollWithWheelDelta), typeof(bool), typeof(ScrollViewer),
{ new FrameworkPropertyMetadata(true, FrameworkPropertyMetadataOptions.Inherits));
obj.SetValue(AlwaysHandleMouseWheelScrollingProperty, value);
} /// <summary>
/// The DependencyProperty of <see cref="EnableScrollingAnimation"/> property.
/// </summary>
/// <summary> public static readonly DependencyProperty EnableScrollingAnimationProperty =
/// The DependencyProperty of <see cref="ScrollWithWheelDelta"/> property. DependencyProperty.RegisterAttached(nameof(EnableScrollingAnimation), typeof(bool), typeof(ScrollViewer),
/// </summary> new FrameworkPropertyMetadata(true, FrameworkPropertyMetadataOptions.Inherits));
public static readonly DependencyProperty ScrollWithWheelDeltaProperty =
DependencyProperty.RegisterAttached(nameof(ScrollWithWheelDelta), typeof(bool), typeof(ScrollViewer), /// <summary>
new FrameworkPropertyMetadata(true, FrameworkPropertyMetadataOptions.Inherits)); /// The DependencyProperty of <see cref="ScrollingAnimationDuration"/> property.
/// </summary>
/// <summary> public static readonly DependencyProperty ScrollingAnimationDurationProperty =
/// The DependencyProperty of <see cref="EnableScrollingAnimation"/> property. DependencyProperty.RegisterAttached(nameof(ScrollingAnimationDuration), typeof(Duration), typeof(ScrollViewer),
/// </summary> new FrameworkPropertyMetadata(new Duration(TimeSpan.FromMilliseconds(250)), FrameworkPropertyMetadataOptions.Inherits), ValidateScrollingAnimationDuration);
public static readonly DependencyProperty EnableScrollingAnimationProperty =
DependencyProperty.RegisterAttached(nameof(EnableScrollingAnimation), typeof(bool), typeof(ScrollViewer), /// <summary>
new FrameworkPropertyMetadata(true, FrameworkPropertyMetadataOptions.Inherits)); /// The DependencyProperty of <see cref="AlwaysHandleMouseWheelScrolling"/> property
/// </summary>
/// <summary> public static readonly DependencyProperty AlwaysHandleMouseWheelScrollingProperty =
/// The DependencyProperty of <see cref="ScrollingAnimationDuration"/> property. DependencyProperty.RegisterAttached(nameof(AlwaysHandleMouseWheelScrolling), typeof(bool), typeof(ScrollViewer), new FrameworkPropertyMetadata(true, FrameworkPropertyMetadataOptions.Inherits));
/// </summary>
public static readonly DependencyProperty ScrollingAnimationDurationProperty = /// <summary>
DependencyProperty.RegisterAttached(nameof(ScrollingAnimationDuration), typeof(Duration), typeof(ScrollViewer), /// The DependencyProperty of <see cref="MouseScrollDeltaFactor"/> property
new FrameworkPropertyMetadata(new Duration(TimeSpan.FromMilliseconds(250)), FrameworkPropertyMetadataOptions.Inherits), ValidateScrollingAnimationDuration); /// </summary>
public static readonly DependencyProperty MouseScrollDeltaFactorProperty =
/// <summary> DependencyProperty.Register(nameof(MouseScrollDeltaFactor), typeof(double), typeof(ScrollViewer), new PropertyMetadata(1.0));
/// The DependencyProperty of <see cref="AlwaysHandleMouseWheelScrolling"/> property
/// </summary> /// <summary>
public static readonly DependencyProperty AlwaysHandleMouseWheelScrollingProperty = /// The DependencyProperty of <see cref="TouchpadScrollDeltaFactor"/> property
DependencyProperty.RegisterAttached(nameof(AlwaysHandleMouseWheelScrolling), typeof(bool), typeof(ScrollViewer), new FrameworkPropertyMetadata(true, FrameworkPropertyMetadataOptions.Inherits)); /// </summary>
public static readonly DependencyProperty TouchpadScrollDeltaFactorProperty =
/// <summary> DependencyProperty.Register(nameof(TouchpadScrollDeltaFactor), typeof(double), typeof(ScrollViewer), new PropertyMetadata(1.0));
/// The DependencyProperty of <see cref="MouseScrollDeltaFactor"/> property
/// </summary> private static bool ValidateScrollingAnimationDuration(object value)
public static readonly DependencyProperty MouseScrollDeltaFactorProperty = => value is Duration duration && duration.HasTimeSpan;
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;
namespace EleCho.WpfSuite namespace EleCho.WpfSuite
{ {
internal static class MathHelper internal static class MathHelper
{ {
internal const double DBL_EPSILON = 2.2204460492503131e-016; internal const double DBL_EPSILON = 2.2204460492503131e-016;
public static bool AreClose(double value1, double value2) => public static bool AreClose(double value1, double value2) =>
// ReSharper disable once CompareOfFloatsByEqualityOperator // ReSharper disable once CompareOfFloatsByEqualityOperator
value1 == value2 || IsVerySmall(value1 - value2); 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) public static bool GreaterThanOrClose(double value1, double value2)
{ {
if (value1 <= value2) if (value1 <= value2)
{ {
return AreClose(value1, value2); return AreClose(value1, value2);
} }
return true; 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) public static bool LessThanOrClose(double value1, double value2)
{ {
if (value1 >= value2) if (value1 >= value2)
{ {
return AreClose(value1, value2); return AreClose(value1, value2);
} }
return true; return true;
} }
public static double EnsureRange(double value, double? min, double? max) public static double EnsureRange(double value, double? min, double? max)
{ {
if (min.HasValue && value < min.Value) if (min.HasValue && value < min.Value)
{ {
return min.Value; return min.Value;
} }
if (max.HasValue && value > max.Value) if (max.HasValue && value > max.Value)
{ {
return max.Value; return max.Value;
} }
return value; return value;
} }
public static double SafeDivide(double lhs, double rhs, double fallback) public static double SafeDivide(double lhs, double rhs, double fallback)
{ {
if (!IsVerySmall(rhs)) if (!IsVerySmall(rhs))
{ {
return lhs / rhs; return lhs / rhs;
} }
return fallback; return fallback;
} }
} }
} }

8
EleCho.WpfSuite/Themes/Generic.xaml

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

196
EleCho.WpfSuite/Utilities/ScrollViewerUtils.cs

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

34
EleCho.WpfSuite/ValueConverters/FallbackConverter.cs

@ -4,23 +4,23 @@ using System.Windows;
namespace EleCho.WpfSuite namespace EleCho.WpfSuite
{ {
/// <summary> /// <summary>
/// Fallback between multiple values, return the first non-null value /// Fallback between multiple values, return the first non-null value
/// </summary> /// </summary>
public class FallbackConverter : SingletonMultiValueConverterBase<FallbackConverter> public class FallbackConverter : SingletonMultiValueConverterBase<FallbackConverter>
{ {
/// <inheritdoc/> /// <inheritdoc/>
public override object? Convert(object?[] values, Type targetType, object? parameter, CultureInfo culture) public override object? Convert(object?[] values, Type targetType, object? parameter, CultureInfo culture)
{ {
foreach (var value in values) foreach (var value in values)
{ {
if (value is not null && if (value is not null &&
value != DependencyProperty.UnsetValue) value != DependencyProperty.UnsetValue)
return value; return value;
} }
return null; return null;
} }
} }
} }

28
EleCho.WpfSuite/ValueConverters/MultiValueConverterBase.cs

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

26
EleCho.WpfSuite/ValueConverters/SingletonMultiValueConverterBase.cs

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

Loading…
Cancel
Save