Wpf scrolling canvas using the mouse 29.03.12
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
- 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
If we leave the ScrollViewers Horitzontal and Vertical Offsets at 0
Then add a Canvas to the ScrollViewer
<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" /> </Canvas> </ScrollViewer>
We get the follwing output
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)
So all we need to do is change the offsets in relation to the users mouse. To change the offset you use.
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 > Scroller.ViewportHeight - 10 Then Scroller.ScrollToVerticalOffset(Scroller.VerticalOffset + 2) ElseIf currentMousePoint.Y < 10 Then Scroller.ScrollToVerticalOffset(Scroller.VerticalOffset - 2) End If If currentMousePoint.X > Scroller.ViewportWidth - 10 Then Scroller.ScrollToHorizontalOffset(Scroller.HorizontalOffset + 2) ElseIf currentMousePoint.X < 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.
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.