在WPF通过右键拖动控制图像缩放
最近在做一个简单的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 }
运行效果