How to enable precision/smooth scrolling in a WPF app on Windows in C# and VB
The Windows Presentation Foundation, or WPF for short is a powerful platform for creating applications in Windows. Introduced in the .NET Framework 3.0 along with Windows Vista in 2006, WPF included an overhault to rendering user interfaces compared to its alternatives at the time, such as GDI (Graphics Driver Interface) and Windows Forms.
Although modern back in 2006, WPF is starting to show its age in modern versions of Windows. One of the areas where WPF shows its age is in scrolling. Although still common, the traditional mouse and keyboard is not the only way to control a Windows computer - touch screens, pens and touchpads are other ways in which a user can send input to a computer.
If you have ever tried scrolling a scroll viewer in WPF using a touchpad or precision mouse, you would have noticed how over sensitive the scrolling is; this is not an issue with the mouse or touchpad, nor is it an issue with Windows, this is an issue with WPF ignoring an important value, known as the delta value. Whenever Windows sends scroll wheel messages, it includes the delta value, which determines how far content should scroll, the trouble is that WPF just ignores this value. However, the good news is that WPF still reads this value, it just doesn't do anything with it.
To enable precision scrolling, all we need to do is override the scrolling behaviour of a scroll viewer using the PreviewMouseWheel event. Now, you can do this to any scroll viewer you want, but for this example we will do it in a style in the App.xaml/Application.xaml file so that we can enable precision scrolling on all scroll viewers.
Firstly, in the App.xaml or Application.xaml file, add this code under <Application.Resources>:
<EventSetter Event="PreviewMouseWheel" Handler="ScrollViewer_PreviewMouseWheel"/>
Now right click on "ScrollViewer_PreviewMouseWheel" and select "Go to Definition". This should take you to App.xaml.cs or Application.xaml.vb, depending on what language you are using. Now, here is the code you want inside the event handler method. Feel free to experiment with it, change it and tidy it up if you desire.
// Try catches here just to ensure app does not crash and instead falls back to default WPF scrolling behaviour if an exception occurs here for whatever reason if an exception occurs here for whatever reason
// Disables custom scroll handling when scroll by one screen at a time is enabled in mouse settings. Feel free to handle this yourself if you wish.
if (System.Windows.Forms.SystemInformation.MouseWheelScrollLines == -1)
e.Handled = false;
// Scrolls the scroll viewer according to the delta value and the user's scrolling settings
System.Windows.Controls.ScrollViewer SenderScrollViewer = (System.Windows.Controls.ScrollViewer)sender;
SenderScrollViewer.ScrollToVerticalOffset(SenderScrollViewer.VerticalOffset - e.Delta * 10 * System.Windows.Forms.SystemInformation.MouseWheelScrollLines / (double)120);
e.Handled = true;
' Try catches here just to ensure app does not crash and instead falls back to default WPF scrolling behaviour if an exception occurs here for whatever reason
' Disables custom scroll handling when scroll by one screen at a time is enabled in mouse settings. Feel free to handle this yourself if you wish.
If System.Windows.Forms.SystemInformation.MouseWheelScrollLines = -1 Then
e.Handled = False
' Scrolls the scroll viewer according to the delta value and the user's scrolling settings
Dim SenderScrollViewer As System.Windows.Controls.ScrollViewer = sender
SenderScrollViewer.ScrollToVerticalOffset(SenderScrollViewer.VerticalOffset - e.Delta * 10 * System.Windows.Forms.SystemInformation.MouseWheelScrollLines / 120)
e.Handled = True
Tip: If you get errors relating to the lines that reference Windows Forms and you are using .Net Framework, go to the solution explorer, right click References, click Add Reference..., select Assemblies, search up Forms and add 'System.Windows.Forms'. If you are using .Net Core and have this issue, right click the project file and select 'Edit Project File' and add ' <UseWindowsForms>true</UseWindowsForms>' to '<PropertyGroup>' at the start of the file.
Post a Comment