实现效果:
实现步骤:
1、首先定义拖拽改变类型枚举:
/// <summary>
/// 拖动改变类型
/// </summary>
public enum ChangeType
{
Move = 0,// 移动
ChangeLeftTop = 1,//左上
ChangeRightTop = 2,//右上
ChangeRightBottom = 3,//右下
ChangeLeftBottom = 4,//左下
Other = 5//其他
}
2、修改MyImage自定义控件
(1)添加全局变量:
public ChangeType changeType;//变换类型
private bool isEnter = false;//是否鼠标进入
private bool isCanDragSize = false;//是否可以改变大小
private Rect LTrect, LBrect, RTrect, RBrect;//左上、左下、右上、右下四个方向的矩形
(2)重绘时在图片四个角绘制四个小矩形表示可拖拽改变大小的四个方向:
/// <summary>
/// 重绘
/// </summary>
protected override void OnRender(DrawingContext dc)
{
base.OnRender(dc);
if (IsSelect)
{
try
{
//绘制边框
Rect rect = new Rect(0, 0, this.Width, this.Height);
Pen p = new Pen(new SolidColorBrush(Colors.Red), 2);
p.DashStyle = DashStyles.Solid;
p.StartLineCap = PenLineCap.Triangle;
dc.DrawRectangle(Brushes.Transparent, p, rect);
//在4个角画出对应的表示方向的小方块
dc.DrawRectangle(new SolidColorBrush(Colors.Red), p, new Rect(0, 0, 5, 5));
dc.DrawRectangle(new SolidColorBrush(Colors.Red), p, new Rect(this.Width - 5, 0, 5, 5));
dc.DrawRectangle(new SolidColorBrush(Colors.Red), p, new Rect(0, this.Height - 5, 5, 5));
dc.DrawRectangle(new SolidColorBrush(Colors.Red), p, new Rect(this.Width - 5, this.Height - 5, 5, 5));
}
catch { }
}
}
(3)注册相关鼠标事件:
public MyImage()
{
this.Stretch = Stretch.Fill;//需要设置Stretch属性,避免拖拽改变宽高时出现异常
this.MouseLeftButtonDown += MyImage_MouseLeftButtonDown;
this.MouseLeftButtonUp += MyImage_MouseLeftButtonUp;
this.MouseEnter += MyImage_MouseEnter;
this.MouseLeave += MyImage_MouseLeave;
this.MouseMove += MyImage_MouseMove;
}
/// <summary>
/// 鼠标按下
/// </summary>
private void MyImage_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
//获取当前坐标
Point p = e.GetPosition(this);
//获取四个方向的矩形
GetESWNRect();
//获取位置
int x = (int)Canvas.GetLeft(this);
int y = (int)Canvas.GetTop(this);
isCanDragSize = true;
//左上
if (IsInThis(p.X, p.Y, LTrect))
{
this.Cursor = Cursors.SizeNWSE;
changeType = ChangeType.ChangeLeftTop;
}
//右上
else if (IsInThis(p.X, p.Y, RTrect))
{
this.Cursor = Cursors.SizeNESW;
changeType = ChangeType.ChangeRightTop;
}
//左下
else if (IsInThis(p.X, p.Y, LBrect))
{
this.Cursor = Cursors.SizeNESW;
changeType = ChangeType.ChangeLeftBottom;
}
//右下
else if (IsInThis(p.X, p.Y, RBrect))
{
this.Cursor = Cursors.SizeNWSE;
changeType = ChangeType.ChangeRightBottom;
}
//中心
else if (p.X > 5 && p.X < this.Width - 5 && p.Y > 5 && p.Y < this.Height - 5)
{
this.Cursor = Cursors.SizeAll;
changeType = ChangeType.Move;
}
else
{
this.Cursor = Cursors.Arrow;
}
}
/// <summary>
/// 鼠标抬起
/// </summary>
private void MyImage_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
isCanDragSize = false;
}
/// <summary>
/// 鼠标进入
/// </summary>
private void MyImage_MouseEnter(object sender, MouseEventArgs e)
{
isEnter = true;
this.Cursor = Cursors.SizeAll;
this.InvalidateVisual();
}
/// <summary>
/// 鼠标移出
/// </summary>
private void MyImage_MouseLeave(object sender, MouseEventArgs e)
{
isEnter = false;
this.Cursor = Cursors.No;
this.InvalidateVisual();
}
/// <summary>
/// 鼠标移动
/// </summary>
private void MyImage_MouseMove(object sender, MouseEventArgs e)
{
if (!isEnter)
return;
//获取鼠标移动中的坐标
Point p = e.GetPosition(this);
//获取四个方向的矩形
GetESWNRect();
//获取当前位置
int x = (int)Canvas.GetLeft(this);
int y = (int)Canvas.GetTop(this);
if (!isCanDragSize)
{
//左上
if (IsInThis(p.X, p.Y, LTrect))
{
this.Cursor = Cursors.SizeNWSE;
changeType = ChangeType.ChangeLeftTop;
}
//右上
else if (IsInThis(p.X, p.Y, RTrect))
{
this.Cursor = Cursors.SizeNESW;
changeType = ChangeType.ChangeRightTop;
}
//左下
else if (IsInThis(p.X, p.Y, LBrect))
{
this.Cursor = Cursors.SizeNESW;
changeType = ChangeType.ChangeLeftBottom;
}
//右下
else if (IsInThis(p.X, p.Y, RBrect))
{
this.Cursor = Cursors.SizeNWSE;
changeType = ChangeType.ChangeRightBottom;
}
//中心
else if (p.X > 5 && p.X < this.Width - 5 && p.Y > 5 && p.Y < this.Height - 5)
{
this.Cursor = Cursors.SizeAll;
changeType = ChangeType.Move;
}
else
{
this.Cursor = Cursors.Arrow;
}
return;
}
}
/// <summary>
/// 指定的坐标是否在矩形里
/// </summary>
public bool IsInThis(double x, double y, Rect rect)
{
return x >= rect.X && x <= rect.X + rect.Width && y >= rect.Y && y <= rect.Y + rect.Height;
}
/// <summary>
/// 获得4个方向的矩形
/// </summary>
public void GetESWNRect()
{
double x = Canvas.GetLeft(this);
double y = Canvas.GetTop(this);
int localArea = 5;//单个角落方块区域的大小
LTrect = new Rect(0, 0, localArea, localArea);
LBrect = new Rect(0, (this.Height - localArea) <= 0 ? 0 : (this.Height - localArea), localArea, localArea);
RTrect = new Rect((this.Width - localArea) <= 0 ? 0 : (this.Width - localArea), 0, localArea, localArea);
RBrect = new Rect((this.Width - localArea) <= 0 ? 0 : (this.Width - localArea), (this.Height - localArea) <= 0 ? 0 : (this.Height - localArea), localArea, localArea);
}
3、主窗体Canvas添加鼠标移动事件:
<Canvas x:Name="mainCanvas" Grid.Row="0" Grid.RowSpan="2" Grid.Column="0" Background="White" Width="960" Height="720" Margin="10,5,0,0"
HorizontalAlignment="Left" VerticalAlignment="Top" ClipToBounds="True"
MouseLeftButtonDown="mainCanvas_MouseLeftButtonDown" MouseLeftButtonUp="mainCanvas_MouseLeftButtonUp" MouseMove="mainCanvas_MouseMove">
<Image x:Name="imgFont"></Image>
<local:MyImage x:Name="imgPic"></local:MyImage>
</Canvas>
4、主窗体交互类:
(1)添加全局变量,记录鼠标移动前图片的位置、大小等:
private Point pBefore = new Point();//鼠标点击前坐标
private Point eBefore = new Point();//图片移动前坐标
private double wBefore;//图片改变大小前宽
private double hBefore;//图片改变大小前高
private int minImgValue = 10;//图片最小宽高
private bool IsCanMove = false;//是否可以移动
(2)分别实现鼠标按下、抬起、移动等事件逻辑:
/// <summary>
/// 鼠标按下
/// </summary>
private void mainCanvas_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (e.OriginalSource.GetType() == typeof(MyImage))
{
MyImage img = (MyImage)e.OriginalSource;
//获取点击前鼠标坐标
this.pBefore = e.GetPosition(this.mainCanvas);
//获取点击图片的坐标和位置
this.eBefore = new Point(Canvas.GetLeft(img), Canvas.GetTop(img));
this.wBefore = img.Width;
this.hBefore = img.Height;
//设置为可移动
IsCanMove = true;
//鼠标捕获此图片
img.CaptureMouse();
img.IsSelect = true;
img.InvalidateVisual();
SetOtherUnSelect(img);
//改变鼠标样式
this.Cursor = System.Windows.Input.Cursors.SizeAll;
}
else
{
SetOtherUnSelect();
}
}
/// <summary>
/// 鼠标抬起
/// </summary>
private void mainCanvas_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
if (e.OriginalSource.GetType() == typeof(MyImage))
{
MyImage img = (MyImage)e.OriginalSource;
//设置为不可移动
IsCanMove = false;
//鼠标释放此图片
img.ReleaseMouseCapture();
img.InvalidateVisual();
this.Cursor = System.Windows.Input.Cursors.Arrow;
}
}
/// <summary>
/// 鼠标移动
/// </summary>
private void mainCanvas_MouseMove(object sender, System.Windows.Input.MouseEventArgs e)
{
if (!IsCanMove)
return;
if (e.OriginalSource != null && e.LeftButton == MouseButtonState.Pressed)
{
if (e.OriginalSource.GetType() == typeof(MyImage))
{
MyImage img = (MyImage)e.OriginalSource;
if (IsCanMove && img != null)
{
MoveChange(e, img.changeType);
}
}
else
{
base.OnMouseMove(e);
}
}
else
this.Cursor = System.Windows.Input.Cursors.Arrow;
}
/// <summary>
/// 移动改变坐标或大小
/// </summary>
private void MoveChange(System.Windows.Input.MouseEventArgs e, ChangeType changeType)
{
try
{
switch (changeType)
{
case ChangeType.ChangeLeftTop:
setLTvp(e);
break;
case ChangeType.ChangeRightTop:
setRTvp(e);
break;
case ChangeType.ChangeRightBottom:
setRBvp(e);
break;
case ChangeType.ChangeLeftBottom:
setLBvp(e);
break;
case ChangeType.Move:
MyImage img = (MyImage)e.OriginalSource;
if (img != null)
MoveImage(e);
break;
}
}
catch (Exception ex)
{
}
}
/// <summary>
/// 移动对象
/// </summary>
public void MoveImage(System.Windows.Input.MouseEventArgs e)
{
MyImage img = (MyImage)e.OriginalSource;
//获取鼠标移动中的坐标
Point p = e.GetPosition(this.mainCanvas);
//计算拖拽距离
double dragx = p.X - pBefore.X;
double dragy = p.Y - pBefore.Y;
//当拖拽距离大于一定范围时改变控件位置
if(Math.Abs(dragx) > 5 || Math.Abs(dragy) > 5)
{
Canvas.SetLeft(img, eBefore.X + dragx);
Canvas.SetTop(img, eBefore.Y + dragy);
img.InvalidateVisual();
}
}
/// <summary>
/// 左上角拖动
/// </summary>
public void setLTvp(System.Windows.Input.MouseEventArgs e)
{
//获取鼠标移动中的坐标
Point p = e.GetPosition(this);
if (e.OriginalSource.GetType() == typeof(MyImage))
{
MyImage img = (MyImage)e.OriginalSource;
double changeX = p.X - pBefore.X;
double changeY = p.Y - pBefore.Y;
if ((wBefore - changeX) > minImgValue)
{
Canvas.SetLeft(img, eBefore.X + changeX);
img.Width = wBefore - changeX;
}
else
{
img.Width = minImgValue;
}
if ((hBefore - changeY) > minImgValue)
{
Canvas.SetTop(img, eBefore.Y + changeY);
img.Height = hBefore - changeY;
}
else
{
img.Height = minImgValue;
}
}
}
/// <summary>
/// 右上角拖动
/// </summary>
public void setRTvp(System.Windows.Input.MouseEventArgs e)
{
//获取鼠标移动中的坐标
Point p = e.GetPosition(this);
if (e.OriginalSource.GetType() == typeof(MyImage))
{
MyImage img = (MyImage)e.OriginalSource;
double changeX = p.X - pBefore.X;
double changeY = p.Y - pBefore.Y;
img.Width = (wBefore + changeX) > minImgValue ? wBefore + changeX : minImgValue;
if ((hBefore - changeY) > minImgValue)
{
Canvas.SetTop(img, eBefore.Y + changeY);
img.Height = hBefore - changeY;
}
else
{
img.Height = minImgValue;
}
}
}
/// <summary>
/// 左下角拖动
/// </summary>
public void setLBvp(System.Windows.Input.MouseEventArgs e)
{
//获取鼠标移动中的坐标
Point p = e.GetPosition(this);
if (e.OriginalSource.GetType() == typeof(MyImage))
{
MyImage img = (MyImage)e.OriginalSource;
double changeX = p.X - pBefore.X;
double changeY = p.Y - pBefore.Y;
if ((wBefore - changeX) > minImgValue)
{
Canvas.SetLeft(img, eBefore.X + changeX);
img.Width = wBefore - changeX;
}
else
{
img.Width = minImgValue;
}
img.Height = (hBefore + changeY) > minImgValue ? hBefore + changeY : minImgValue;
}
}
/// <summary>
/// 右下角拖动
/// </summary>
public void setRBvp(System.Windows.Input.MouseEventArgs e)
{
//获取鼠标移动中的坐标
Point p = e.GetPosition(this);
if (e.OriginalSource.GetType() == typeof(MyImage))
{
MyImage img = (MyImage)e.OriginalSource;
double changeX = p.X - pBefore.X;
double changeY = p.Y - pBefore.Y;
img.Width = (wBefore + changeX) > minImgValue ? wBefore + changeX : minImgValue;
img.Height = (hBefore + changeY) > minImgValue ? hBefore + changeY : minImgValue;
}
}
/// <summary>
/// 设置其他为未选择状态
/// </summary>
public void SetOtherUnSelect(object myImage = null)
{
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(this.mainCanvas); i++)
{
if (VisualTreeHelper.GetChild(this.mainCanvas, i).GetType() == typeof(MyImage))
{
MyImage child = (MyImage)VisualTreeHelper.GetChild(this.mainCanvas, i);
if (myImage == null)
{
child.IsSelect = false;
child.InvalidateVisual();
}
else if (myImage != child)
{
if (child.IsSelect)
{
child.IsSelect = false;
child.InvalidateVisual();
}
}
}
}
}
到此为止,DrawDemo工程的主要功能已经完成了,现在把Canvas的内容保存为图片输出,步骤:
1、主窗体添加保存控件:
<Label Grid.Row="5" Grid.Column="0" Content="保存图片" VerticalAlignment="Center" HorizontalAlignment="Left"></Label>
<Button x:Name="btnSaveImg" Grid.Row="5" Grid.Column="1" Content="保存" VerticalAlignment="Center" HorizontalAlignment="Left" Height="26" Width="80" Click="btnSaveImg_Click"></Button>
2、添加输出图片方法,这里为了简便固定输出位置:
/// <summary>
/// 将Canvas内容输出为位图
/// </summary>
public RenderTargetBitmap ExportToBitmap()
{
try
{
Canvas surface = this.mainCanvas;
Size size = new Size(surface.Width, surface.Height);
surface.Measure(size);
surface.Arrange(new Rect(size));
RenderTargetBitmap renderBitmap =
new RenderTargetBitmap(
(int)size.Width,
(int)size.Height,
96d,
96d,
PixelFormats.Pbgra32);
renderBitmap.Render(surface);
return renderBitmap;
}
catch (Exception ex)
{
return null;
}
}
/// <summary>
/// 保存为png图片
/// </summary>
private void btnSaveImg_Click(object sender, RoutedEventArgs e)
{
RenderTargetBitmap getSource = ExportToBitmap();
BitmapImage getImage = ImageHelper.ConventToBitmapImage(getSource);
string savePath = @"E:\图片\小图\example1.png";
ImageHelper.SaveBitmapImageAsPng(getImage, savePath);
}
3、输出图片效果:
相关博文:
WPF中GDI+图形图像的绘制:(一)绘制文本——动态设置字体、大小、颜色
WPF中GDI+图形图像的绘制:(二)绘制文本——字体描边、渐变、图片叠加
WPF中GDI+图形图像的绘制:(三)绘制图像——实现黑白、浮雕、锐化效果
WPF中GDI+图形图像的绘制:(四)绘制图像——水平垂直镜像与中心旋转
WPF中GDI+图形图像的绘制:(五)绘制图像——蒙板效果
WPF中GDI+图形图像的绘制:(六)绘制图像——鼠标选中后绘制边框
WPF中GDI+图形图像的绘制:(七)绘制图像——鼠标拖动改变位置和大小
WPF中GDI+图形图像的绘制:(八)位置坐标和宽高与控件绑定展示