Click here to Skip to main content
15,867,330 members
Articles / Desktop Programming / WPF

Zooming and panning in WPF with fixed focus

Rate me:
Please Sign up or sign in to vote.
4.83/5 (16 votes)
14 Mar 2011CPOL2 min read 67.2K   3.8K   23   16
How to do zooming and panning in WPF with fixed focus.

Zoomed_Out.PNG

Introduction

I have found quite a few articles about zooming into a fixed point. I have also tried many solutions, some worked, some did not. The ones that did work were too complicated to my needs. The ones that did not work could not hold focus or they overlapped other parts of the screen when zooming in. Another common problem was when panning. Many solutions did not record the original position of the mouse, so when you started panning, your image would make a sudden jump so you held on to the top left corner and not where your mouse was before. In my Windows Forms solution, one of the biggest issues was to limit the image size so that it wouldn't overlap other parts; in WPF, it was much easier as I could set the "cliptobounds" to accomplish the same.

Zoomed_In.PNG

Using the code

After a lot of trials and errors, I ended up with a quite simple code.

A few event handlers to catch some mouse events:

C#
WPFWindow.MouseWheel += MainWindow_MouseWheel;
image.MouseLeftButtonDown += image_MouseLeftButtonDown;
image.MouseLeftButtonUp += image_MouseLeftButtonUp;
image.MouseMove += image_MouseMove;

First, I declare some global variables. Start to store the position of the mouse when the mouse button is first clicked, and origin to store the original offset of the image before it was moved.

C#
private Point origin;  // Original Offset of image
private Point start;   // Original Position of the mouse

MouseDown sets the two variables.

C#
private void image_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
    if (image.IsMouseCaptured) return;
    image.CaptureMouse();

    start = e.GetPosition(border);
    origin.X = image.RenderTransform.Value.OffsetX;
    origin.Y = image.RenderTransform.Value.OffsetY;
}

MouseMove takes care of the panning. I move the image around relative to the position saved in the MouseDown event. I just set the offset to the difference between the original position of the mouse and the current position of the mouse, and add that value to the original offset.

C#
private void image_MouseMove(object sender, MouseEventArgs e)
{
    if (!image.IsMouseCaptured) return;
    Point p = e.MouseDevice.GetPosition(border);

    Matrix m = image.RenderTransform.Value;
    m.OffsetX = origin.X + (p.X - start.X);
    m.OffsetY = origin.Y + (p.Y - start.Y);

    image.RenderTransform = new MatrixTransform(m);
}

MouseWheel does the actual zooming. It uses ScaleAtPrepend which not only does the zooming, but also keeps the focus. This was a lot easier than the Windows Forms version.

C#
private void MainWindow_MouseWheel(object sender, MouseWheelEventArgs e)
{
    Point p = e.MouseDevice.GetPosition(image);

    Matrix m = image.RenderTransform.Value;
    if (e.Delta > 0)
        m.ScaleAtPrepend(1.1, 1.1, p.X, p.Y);
    else
        m.ScaleAtPrepend(1/1.1, 1/1.1, p.X, p.Y);

    image.RenderTransform = new MatrixTransform(m);
}

Points of Interest

It is important to notice the "cliptobounds" in the XAML. If it is true, it ensures that the image is held within the border and doesn't overlap other parts of the window.

XML
<border grid.row="1" name="border" cliptobounds="True">
    <img name="image" opacity="1" 
       source="/WPF%20Image%20Pan%20and%20Zoom;component/Images/test.tif" />
</border>

History

  • Initial release.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior) DSR
Denmark Denmark
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
QuestionSimple and useful ! Pin
TheGEZ29-Jan-21 2:40
TheGEZ29-Jan-21 2:40 
PraiseExactly what I needed! Pin
DickIC21-Sep-20 9:08
DickIC21-Sep-20 9:08 
GeneralMy vote of 5 Pin
Member 1404659020-Nov-18 7:37
Member 1404659020-Nov-18 7:37 
QuestionAttached controls to picture box Pin
Vitorbarros219-Aug-16 3:07
professionalVitorbarros219-Aug-16 3:07 
QuestionOnMouseWheel improvement Pin
Jan Rudolph30-Mar-16 4:20
Jan Rudolph30-Mar-16 4:20 
QuestionWell done :) i'm so happy Pin
Member 1130641912-Dec-14 5:27
Member 1130641912-Dec-14 5:27 
GeneralAwesome job! Pin
Dale Barnard25-Nov-14 6:38
Dale Barnard25-Nov-14 6:38 
BugIssue on re-size window Pin
Ujjwal Sud2-Oct-13 0:40
Ujjwal Sud2-Oct-13 0:40 
QuestionExcellaent Work Pin
prasad@123429-Apr-13 20:57
prasad@123429-Apr-13 20:57 
GeneralMy vote of 4 Pin
santosha epili11-Feb-13 18:30
santosha epili11-Feb-13 18:30 
GeneralNeed a help Pin
DavJes21-Mar-11 1:41
DavJes21-Mar-11 1:41 
GeneralVery Nice - 5 Pin
David Roh15-Mar-11 6:15
David Roh15-Mar-11 6:15 
Thank you for sharing. - david
GeneralNot bad, easy to implement Pin
Eugen Klerner15-Mar-11 1:51
Eugen Klerner15-Mar-11 1:51 
GeneralRe: Not bad, easy to implement Pin
Lars Pehrsson15-Mar-11 3:46
Lars Pehrsson15-Mar-11 3:46 
GeneralNice Pin
DavJes15-Mar-11 0:38
DavJes15-Mar-11 0:38 
GeneralMy vote of 5 Pin
gazette214-Mar-11 17:46
gazette214-Mar-11 17:46 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.