最近在做一个简单的Dicom查看器工具。

项目地址:https://github.com/zhaotianff/ImageViewer.git

遇到一个需要就是需要通过右键对图像进行缩放。

 

一开始我是通过处理MouseMove事件,然后再判断右键按下,再通过鼠标移动的方向及偏移进行缩放。

例如,右键按住鼠标往左下角移动是放大,右上角移动是缩小。

1 private void Border_MouseMove(object sender, MouseEventArgs e)2 {3     if(e.RightButton == MouseButtonState.Pressed)4     {5         var point = e.GetPosition(this.image);6 7         if (LastZoomPoint.X == 0 && LastZoomPoint.Y == 0)8         {9             LastZoomPoint = point;
10             return;
11         }
12 
13         var xPos = point.X - LastZoomPoint.X;
14         var yPos = point.Y - LastZoomPoint.Y;
15 
16         if (Math.Abs(xPos) < 10 && Math.Abs(yPos) < 10)
17             return;
18 
21         var ratio = currentRatio;
22         if (xPos < 0)
23             ratio *= 1.1f;
24         else
25             ratio *= 0.9f;
26 
27         LimitRatio(ref ratio);
28 
29         scaleTransform.CenterX = this.image.ActualWidth / 2.0;
30         scaleTransform.CenterY = this.image.ActualHeight / 2.0;
31 
32         scaleTransform.ScaleX *= ratio / currentRatio;
33         scaleTransform.ScaleY *= ratio / currentRatio;
34 
35         currentRatio = ratio;
36         LastZoomPoint = point;
37     }
38 }

 

但是这种方式实现出遇到一个问题,就是鼠标滑过其它控件或者超出窗口,就会导致缩放异常。

 

查了下资料,正确的实现方式应该如下:

1、处理MouseDown事件,然后调用元素的CaptureMouse函数,将鼠标强制捕获到指定元素

2、处理MouseMove事件,判断移动方向,及delta,进行缩放

3、处理MouseUp事件,调用元素的ReleaseMouseCapture函数,释放捕获。

 

下面我们用一个示例程序演示一下

 

首先我们创建一个界面,界面上放置一个Image控件

1     <Grid>
2         <Image Source="e.jpeg" Stretch="Fill" MouseRightButtonDown="Image_MouseRightButtonDown" MouseRightButtonUp="Image_MouseRightButtonUp" MouseMove="Image_MouseMove" Name="image" LayoutUpdated="image_LayoutUpdated">
3             <Image.RenderTransform>
4                 <ScaleTransform ScaleX="1" ScaleY="1"></ScaleTransform>
5             </Image.RenderTransform>
6         </Image> 
7     </Grid>

 

全局变量

1    private Point startPoint;
2    private bool isDragging = false;

 

处理RightMouseDown事件

获取鼠标按下的起始点并捕获鼠标

1   private void Image_MouseRightButtonDown(object sender, MouseButtonEventArgs e)
2   {
3       startPoint = e.GetPosition(this);
4       isDragging = true;
5       image.CaptureMouse();
6   }

 

处理RightMouseUp事件

释放鼠标的捕获

1         private void Image_MouseRightButtonUp(object sender, MouseButtonEventArgs e)
2         {
3             isDragging = false;
4             image.ReleaseMouseCapture();
5         }

 

处理LayoutUpdated事件

这个事件的作用是更新缩放的中心点

1         /// <summary>2         /// 布局更新,更新缩放的中心点为控件的中心3         /// </summary>4         /// <param name="sender"></param>5         /// <param name="e"></param>6         private void image_LayoutUpdated(object sender, EventArgs e)7         {8             var scaleTransform = this.image.RenderTransform as ScaleTransform;9             scaleTransform.CenterX = this.image.ActualWidth / 2;
10             scaleTransform.CenterY = this.image.ActualHeight / 2;
11         }

 

处理MouseMove事件

这里就是缩放的核心逻辑

1 private void Image_MouseMove(object sender, MouseEventArgs e)2 {3     if (isDragging)4     {5         Point current = e.GetPosition(this);6 7         double dx = current.X - startPoint.X;8         double dy = current.Y - startPoint.Y;9 
10         double zoomDelta = (dy - dx) * 0.005;
11 
12         var scaleTransform = this.image.RenderTransform as ScaleTransform;
13 
14         double newScaleX = scaleTransform.ScaleX + zoomDelta;
15         double newScaleY = scaleTransform.ScaleY + zoomDelta;
16 
17         //限制最大缩放比例
18         newScaleX = Math.Max(0.1, Math.Min(5.0, newScaleX));
19         newScaleY = Math.Max(0.1, Math.Min(5.0, newScaleY));
20 
21         scaleTransform.ScaleX = newScaleX;
22         scaleTransform.ScaleY = newScaleY;
23 
24         startPoint = current;
25     }
26 }

 

运行效果