以当前鼠标坐标的缩放和拖拽的方法,应用较多的有图像预览。
C#和WPF的框架比一些前端 或Java的UI框架,少了很多东西,作为开发者来说,社区生态的确非常重要。
网上关于WPF的资源不多,像基本的缩放和拖拽需要完全自己写代码。代码不复杂,为避免大家重复发明轮子,分享自己的代码给大家。
效果预览:
进入正题
1.前台代码:创建一个ContentControl(控件容器也行)包含一个Image控件。
ContentControl有三个事件,分别是:MouseWheel,MouseDown和MouseMove。
<ScrollViewer HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Disabled" >
<ContentControl MouseWheel="ContentControl_MouseWheel" MouseDown="ContentControl_MouseDown" MouseUp="ContentControl_MouseUp" >
<Image Name="ImgCtl" Margin="-2,2,0,0" />
</ContentControl>
</ScrollViewer>
2. Image控件指定TransformGroup。
所有缩放和平移操作都应用于Image控件。TransformGroup能容纳各种变换。在初始化时它的Children添加了ScaleTransform和TranslateTransform,分别用于缩放和平移的变换。
public TransformGroup transGroup;
private void Window_Loaded(object sender, RoutedEventArgs e)
{
transGroup.Children.Add(new ScaleTransform());
transGroup.Children.Add(new TranslateTransform());
ImgCtl.Rendertransform=transGroup;
}
3. 缩放操作
MouseWheel:监听用户的鼠标滚动事件,进行缩放操作。
private void ContentControl_MouseWheel(object sender, System.Windows.Input.MouseWheelEventArgs e)
{
Control ctl = sender as Control;
System.Windows.Point point = e.GetPosition(ctl);
//滚轮滚动时控制 放大的倍数,没有固定的值,可以根据需要修改。
double scale = e.Delta * 0.002;
ZoomImage(transGroup, point, scale);
}
//对控件进行缩放。
private void ZoomImage(TransformGroup group, Point point, double scale)
{
Point pointToContent = group.Inverse.Transform(point);
ScaleTransform scaleT = group.Children[0] as ScaleTransform;
if (scaleT.ScaleX + scale < 1) return;
scaleT.ScaleX += scale;
scaleT.ScaleY += scale;
TranslateTransform translateT = group.Children[1] as TranslateTransform;
translateT.X = -1 * ((pointToContent.X * scaleT.ScaleX) - point.X);
translateT.Y = -1 * ((pointToContent.Y * scaleT.ScaleY) - point.Y);
}
4. 拖拽操作
MouseDown:监听用户点击事件,记录拖拽前鼠标坐标和Image的坐标。
//用于保存鼠标点击时的位置
System.Windows.Point mousePosition = new System.Windows.Point();
//鼠标点击时控件位置
System.Windows.Point contentCtlPosition = new System.Windows.Point();
private void ContentControl_MouseDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
Control ctl = sender as Control;
mousePosition = e.GetPosition(ctl);
TranslateTransform tt = TransGroup.Children[1] as TranslateTransform;
contentCtlPosition = new Point(tt.X, tt.Y);
}
MouseMove:监听用户是否进行拖拽并做平移变换。
private void MasterScrollViewer_MouseMove(object sender, System.Windows.Input.MouseEventArgs e)
{
if (e.LeftButton == MouseButtonState.Pressed)
{
Control ctl = sender as Control;
Point desPosition = e.GetPosition(ctl);
TranslateTransform transform = transGroup.Children[1] as TranslateTransform;
//控件移动位置的计算方式为:鼠标点击时位置+拖拽的长度(当前坐标-鼠标点击时的坐标).
transform.X = contentCtlPosition.X + (desPosition.X - mousePosition.X);
transform.Y = contentCtlPosition.Y + (desPosition.Y - mousePosition.Y);
}
}
TransformGroup比常见的一个Canvsa父级控件然后Canvas.SetLeft()、Canvas.SetTop()....要方便许多。并且这种写法可以使用MVVM模式,不必再调用Canvas和Image实例。
到此所有操作都已完成。如果不用MVVM模式的写法可以直接略过下面的内容。
MVVM写法:
前台代码:
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
//在例子中使用MVVMLight 。如果不用,command可以用其它写法
xmlns:command="http://www.galasoft.ch/mvvmlight"
<ScrollViewer HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Disabled">
<ContentControl >
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseMove">
<command:EventToCommand Command="{Binding MouseMoveCmd}" PassEventArgsToCommand="True" />
</i:EventTrigger>
<i:EventTrigger EventName="MouseWheel">
<command:EventToCommand Command="{Binding MouseWheelCmd}" PassEventArgsToCommand="True" />
</i:EventTrigger>
<i:EventTrigger EventName="MouseDown">
<command:EventToCommand Command="{Binding MouseDownCmd}" PassEventArgsToCommand="True" />
</i:EventTrigger>
</i:Interaction.Triggers>
<Image Margin="-2,2,0,0" Source="{Binding PreviewImage}" RenderTransform="{Binding TransGroup}" >
</Image>
</ContentControl>
</ScrollViewer>
在VM中:
//鼠标移动命令
public RelayCommand<MouseEventArgs> MouseMoveCmd
{
get
{
return mouseMoveCmd ?? (mouseMoveCmd = new RelayCommand<MouseEventArgs>(OnMouseMove ));
}
private set { }
}
RelayCommand<MouseEventArgs> mouseMoveCmd;
//鼠标滚动命令
public RelayCommand<MouseWheelEventArgs> MouseWheelCmd
{
get
{
return mouseWheelCmd ?? (mouseWheelCmd = new RelayCommand<MouseWheelEventArgs>(OnMouseWheel));
}
private set { }
}
RelayCommand<MouseWheelEventArgs> mouseWheelCmd;
//鼠标点击命令
public RelayCommand<MouseButtonEventArgs> MouseDownCmd
{
get
{
return mouseDownCmd ?? (mouseDownCmd = new RelayCommand<MouseButtonEventArgs>(OnMouseDown));
}
}
RelayCommand<MouseButtonEventArgs> mouseDownCmd;
public TransformGroup TransGroup
{
get
{
return transGroup;
}
set
{
transGroup = value;
RaisePropertyChanged();
}
}
TransformGroup transGroup = new TransformGroup();
//用于保存鼠标点击时的位置
Point mousePosition = new Point();
//鼠标点击时控件位置
Point contentCtlPosition = new Point();
//鼠标滚动,缩放控件。
void OnMouseWheel(MouseWheelEventArgs args)
{
Control ctl = args.Source as Control;
Point point = args.GetPosition(ctl);
//滚轮滚动时控制 放大的倍数
double scale = args.Delta * 0.002;
ZoomImage(transGroup, point, scale);
}
//对控件进行缩放。
private void ZoomImage(TransformGroup group, Point point, double scale)
{
Point pointToContent = group.Inverse.Transform(point);
ScaleTransform scaleT = group.Children[0] as ScaleTransform;
if (scaleT.ScaleX + scale < 1) return;
scaleT.ScaleX += scale;
scaleT.ScaleY += scale;
TranslateTransform translateT = group.Children[1] as TranslateTransform;
translateT.X = -1 * ((pointToContent.X * scaleT.ScaleX) - point.X);
translateT.Y = -1 * ((pointToContent.Y * scaleT.ScaleY) - point.Y);
RaisePropertyChanged("TransGroup");
}
//鼠标点击,记录下点击的位置。
void OnMouseDown(MouseButtonEventArgs args)
{
Control ctl = args.Source as Control;
if (ctl == null)
{
}
mousePosition = args.GetPosition(ctl);
TranslateTransform tt = TransGroup.Children[1] as TranslateTransform;
contentCtlPosition = new Point(tt.X, tt.Y);
}
//鼠标移动,每次移动与上一次的位置相加,并实时更新当前位置。
private void OnMouseMove(System.Windows.Input.MouseEventArgs args)
{
if (args.LeftButton == MouseButtonState.Pressed)
{
Control ctl = args.Source as Control;
Point desPosition = args.GetPosition(ctl);
TranslateTransform transform = transGroup.Children[1] as TranslateTransform;
//控件移动位置的计算方式为:鼠标点击时位置+拖拽的长度(当前坐标-鼠标点击时的坐标).
transform.X = contentCtlPosition.X + (desPosition.X - mousePosition.X);
transform.Y = contentCtlPosition.Y + (desPosition.Y - mousePosition.Y);
RaisePropertyChanged("TransGroup");
}
}