using System.Windows.Input; // ReSharper disable once CheckNamespace namespace WPFluent.Controls; /// /// HCWhite with events depending on actions taken by the /// user. /// public class DynamicScrollBar : System.Windows.Controls.Primitives.ScrollBar { /// /// Identifies the dependency property. /// public static readonly DependencyProperty IsInteractedProperty = DependencyProperty.Register( nameof(IsInteracted), typeof(bool), typeof(DynamicScrollBar), new PropertyMetadata(false, OnIsInteractedChanged)); /// /// Identifies the dependency property. /// public static readonly DependencyProperty IsScrollingProperty = DependencyProperty.Register( nameof(IsScrolling), typeof(bool), typeof(DynamicScrollBar), new PropertyMetadata(false, OnIsScrollingChanged)); /// /// Identifies the dependency property. /// public static readonly DependencyProperty TimeoutProperty = DependencyProperty.Register( nameof(Timeout), typeof(int), typeof(DynamicScrollBar), new PropertyMetadata(1000)); private readonly EventIdentifier _interactiveIdentifier = new(); private bool _isInteracted = false; private bool _isScrolling = false; private static void OnIsInteractedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { if (d is not DynamicScrollBar bar) { return; } if (bar._isInteracted == bar.IsInteracted) { return; } bar._isInteracted = !bar._isInteracted; bar.UpdateScrollAsync(); } private static void OnIsScrollingChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { if (d is not DynamicScrollBar bar) { return; } if (bar._isScrolling == bar.IsScrolling) { return; } bar._isScrolling = !bar._isScrolling; bar.UpdateScrollAsync(); } private async Task UpdateScrollAsync() { var currentEvent = _interactiveIdentifier.GetNext(); var shouldScroll = IsMouseOver || _isScrolling; if (shouldScroll == _isInteracted) { return; } if (!shouldScroll) { await Task.Delay(Timeout); } if (!_interactiveIdentifier.IsEqual(currentEvent)) { return; } SetCurrentValue(IsInteractedProperty, shouldScroll); } /// /// Method reporting the mouse entered this element. /// protected override void OnMouseEnter(MouseEventArgs e) { base.OnMouseEnter(e); UpdateScrollAsync(); } /// /// Method reporting the mouse leaved this element. /// protected override void OnMouseLeave(MouseEventArgs e) { base.OnMouseLeave(e); UpdateScrollAsync(); } /// /// Gets or sets a value indicating whether the user has taken an action related to scrolling. /// public bool IsInteracted { get => (bool)GetValue(IsInteractedProperty); set { if ((bool)GetValue(IsInteractedProperty) != value) { SetValue(IsInteractedProperty, value); } } } /// /// Gets or sets a value indicating whether the user was recently scrolling in the last few seconds. /// public bool IsScrolling { get => (bool)GetValue(IsScrollingProperty); set => SetValue(IsScrollingProperty, value); } /// /// Gets or sets additional delay after which the should be hidden. /// public int Timeout { get => (int)GetValue(TimeoutProperty); set => SetValue(TimeoutProperty, value); } }