Skip to content

Instantly share code, notes, and snippets.

@LeeCampbell
Created October 26, 2012 15:03
Show Gist options
  • Save LeeCampbell/3959289 to your computer and use it in GitHub Desktop.
Save LeeCampbell/3959289 to your computer and use it in GitHub Desktop.
Corrects the ScrollViewer behavior that does not allow parent to scroll once child has exhausted scrolling.
using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
namespace MyLib
{
//http://serialseb.blogspot.co.uk/2007/09/wpf-tips-6-preventing-scrollviewer-from.html
public sealed class ScrollViewerCorrector
{
private static readonly List<MouseWheelEventArgs> ReentrantList = new List<MouseWheelEventArgs>();
public static bool GetFixScrolling(DependencyObject obj)
{
return (bool)obj.GetValue(FixScrollingProperty);
}
public static void SetFixScrolling(DependencyObject obj, bool value)
{
obj.SetValue(FixScrollingProperty, value);
}
public static readonly DependencyProperty FixScrollingProperty =
DependencyProperty.RegisterAttached("FixScrolling", typeof(bool), typeof(ScrollViewerCorrector), new FrameworkPropertyMetadata(false, OnFixScrollingPropertyChanged));
public static void OnFixScrollingPropertyChanged(object sender, DependencyPropertyChangedEventArgs e)
{
var viewer = sender as ScrollViewer;
if (viewer == null)
throw new ArgumentException("The dependency property can only be attached to a ScrollViewer", "sender");
var newValue = (bool) e.NewValue;
if (newValue)
viewer.PreviewMouseWheel += HandlePreviewMouseWheel;
else
viewer.PreviewMouseWheel -= HandlePreviewMouseWheel;
}
private static void HandlePreviewMouseWheel(object sender, MouseWheelEventArgs e)
{
if (e.Handled) return;
var scrollControl = sender as ScrollViewer;
if (scrollControl != null && !ReentrantList.Contains(e))
{
var previewEventArg = new MouseWheelEventArgs(e.MouseDevice, e.Timestamp, e.Delta)
{
RoutedEvent = UIElement.PreviewMouseWheelEvent,
Source = scrollControl
};
ReentrantList.Add(previewEventArg);
var originalSource = e.OriginalSource as UIElement;
if (originalSource != null)
originalSource.RaiseEvent(previewEventArg);
ReentrantList.Remove(previewEventArg);
// at this point if no one else handled the event in our children, we do our job
if (!previewEventArg.Handled &&
(
(e.Delta > 0 && scrollControl.VerticalOffset == 0)
||
(e.Delta <= 0 && scrollControl.VerticalOffset >= scrollControl.ExtentHeight - scrollControl.ViewportHeight)
))
{
e.Handled = true;
var eventArg = new MouseWheelEventArgs(e.MouseDevice, e.Timestamp, e.Delta) {RoutedEvent = UIElement.MouseWheelEvent, Source = scrollControl};
var parent = scrollControl.Parent
?? VisualTreeHelper.GetParent(scrollControl);
((UIElement)parent).RaiseEvent(eventArg);
}
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment