最近在做一个简单的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 }
运行效果