A problem I faced a while ago when using WPF, was how to automatically scroll the Canvas when my mouse reached the bounds of the ScrollViewer.


The idea was to create seamless drawing, on the canvas.


Eventually after numerous failed attempts, I headed to the internet. I found some very good examples but I failed to find any that would keep scrolling regardless of the size of the canvas.


Then I thought about using a timer. This lead to a far easier solution, as this allows for a very controlled approach as a timer ticks at a fixed interval ensuring that scrolling is consistent.


Anyway lets get started


Two of the properties in the ScrollViewer are HorizontalOffset and VerticalOffset.


- HorizontalOffset is how far the the ScrollViewers Viewport is from the left of its content.

- VerticalOffset is how far the ScrollViewers Viewport is from the top of its content


For example:


If we leave the ScrollViewers Horitzontal and Vertical Offsets at 0

Then add a Canvas to the ScrollViewer

And a Rectangle to the canvas with Width and Height set to 100, and  the Canvas.Left and Canvas.Top set to 100.


   <ScrollViewer Name="CanvasScrollViewer" HorizontalScrollBarVisibility="Visible" VerticalScrollBarVisibility="Visible">
     <Canvas Name="MyCanvas" Background="Transparent" Width="2000" Height="2000">
        <Rectangle Canvas.Left="100" Canvas.Top="100" Width="100" Height="100" Fill="Red" />

We get the follwing output


Without offset


But if we change the ScrollViewers horizontal and vertical offset to 100 (we do this in code), and keep everything else the same.


The rectangle is still in the same location on the canvas, but the scrollviewer has scrolled to the top left of the rectangle. (see the scroll bars)


With Offset



So all we need to do is change the offsets in relation to the users mouse. To change the offset you use.


- ScrollViewerName.ScrollToHorizontalOffset(the offset)
- ScrollViewerName.ScrollToVerticalOffset(the offset).


As we are using a timer we  change the offset by a fixed amount each time the timer ticks.
In the following code we are using a DispatchTimer, in order for this to work you need to set an interval for the timer using TimeSpan I used 10000. Then start the time using timername.start() to stop the timer user timername.stop().


    Private Sub dispatcherTimer_Tick(ByVal sender As Object, ByVal e As EventArgs)
        If currentMousePoint.Y &gt; Scroller.ViewportHeight - 10 Then
            Scroller.ScrollToVerticalOffset(Scroller.VerticalOffset + 2)
        ElseIf currentMousePoint.Y &lt; 10 Then
           Scroller.ScrollToVerticalOffset(Scroller.VerticalOffset - 2)
       End If         
        If currentMousePoint.X &gt; Scroller.ViewportWidth - 10 Then
            Scroller.ScrollToHorizontalOffset(Scroller.HorizontalOffset + 2)
        ElseIf currentMousePoint.X &lt; 10 Then
            Scroller.ScrollToHorizontalOffset(Scroller.HorizontalOffset - 2)
        End If
    End Sub

In the code above when the timer ticks it checks the users mouse location in relation to the ScrollViewer.

Then makes the appropriate changes based on the location by either increasing or decreasing the current offset. To get the location, we use the following code.


    Private Sub Scroller_MouseMove(ByVal sender As System.Object, ByVal e As System.Windows.Input.MouseEventArgs)
       currentMousePoint = e.GetPosition(Scroller)
    End Sub

Thats all there is to it really, I wouldn’t reccomend using the code as is though. This is just and example to help you get started with your own implementation.


One problem I came across was when using the Thumbs DragDelta event to move a Thumb, the scrolling worked but the Thumb lagged behind and every so often it would jump to my mouse and get stuck again.


A way round this is to pass the changes you have made to the offsets, into the sub/function you are using to move the thumb, in the same way you would when using the Thumbs DragDelta Event.


In the future I will write another post, containing a more readily usable example. Which you will be able to adjust to your needs or simply use as is, it will also address the problem with thumbs.

Tags: , ,

Categorie(s): Programming, Uncategorized, WPF