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


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

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 and instead falls back to default WPF scrolling behaviour 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.

Bonus: ScrollViewers not scrolling with touch? Have a look at this article here.
Extra bonus: Want to enable more performant and precise scrolling for your WebBrowser controls? Have a look here.

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.

Examples

Scrolling with a touchpad normally in WPF:


Scrolling with a touchpad using the code from this guide in WPF:


The above examples were taken from our app Window Commander.

Follow us to be notified when we release new guides:

Comments

Popular posts from this blog

How to show placeholder text in a WPF TextBox in C# and VB

How to enable dark title bar in WPF and Windows Forms/WinForms apps in C# and VB

How to use modern icons in XAML in WPF on Windows 10 and 11

How to change the colour of a WPF or Windows Forms/WinForms title bar in Windows 11 in C# and VB

Microsoft WebView2: How to check if the WebView2 runtime is installed in C# and VB