How to enable precision scrolling in a WPF app on Windows

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>:


 <Style TargetType="ScrollViewer">

        <EventSetter Event="PreviewMouseWheel" Handler="ScrollViewer_PreviewMouseWheel"/>

 </Style> 

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.

C#:

// Try catches here just to ensure app does not crash if an exception occurs here for whatever reason

try

{

// 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;

   else

    try

        {

         // 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;

                }

                catch

                {

                }

        }

        catch

        {

        }

VB:

' Try catches here just to ensure app does not crash if an exception occurs here for whatever reason

     Try

         ' 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

         Else

             Try

                 ' 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

             Catch

         End Try

         End If

     Catch

     End Try


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.

This snippet is available in Codly. Click the appropriate link below to download the snippet. If you don't have Codly, it is available here in the Microsoft Store.

Follow us to be notified when we release new guides:

Comments

Popular posts from this blog

How to enable dark title bar in Windows Forms and WPF (Windows Presentation Foundation) apps

How to show placeholder text in a WPF textbox