using System.Windows.Controls; using System.Windows.Input; namespace WPFluent.Controls; /// /// A custom ScrollViewer that allows certain mouse events to bubble through when it's inactive. /// public class PassiveScrollViewer : ScrollViewer { /// /// Identifies the dependency property. /// public static readonly DependencyProperty IsScrollSpillEnabledProperty = DependencyProperty.Register( nameof(IsScrollSpillEnabled), typeof(bool), typeof(PassiveScrollViewer), new PropertyMetadata(true)); private bool HasReachedEndOfScrolling(MouseWheelEventArgs e) { var isScrollingUp = e.Delta > 0; var isScrollingDown = e.Delta < 0; var isTopOfViewport = VerticalOffset == 0; var isBottomOfViewport = VerticalOffset >= ScrollableHeight; return isScrollingUp && isTopOfViewport || isScrollingDown && isBottomOfViewport; } private bool IsContentSmallerThanViewport => ScrollableHeight <= 0; private bool IsVerticalScrollingDisabled => VerticalScrollBarVisibility == ScrollBarVisibility.Disabled; protected override void OnMouseWheel(MouseWheelEventArgs e) { if(IsVerticalScrollingDisabled || IsContentSmallerThanViewport || IsScrollSpillEnabled && HasReachedEndOfScrolling(e)) { return; } base.OnMouseWheel(e); } /// /// Gets or sets a value indicating whether blocked inner scrolling should be propagated forward. /// public bool IsScrollSpillEnabled { get { return (bool)GetValue(IsScrollSpillEnabledProperty); } set { SetValue(IsScrollSpillEnabledProperty, value); } } }