2021-11-07 乐帮网
wpf
首先说明示例代码的环境:.Net Core WPF + Net 5(.Net Core 3 同样适用) 最后会提供源码下载。
实现的基本功能:使用鼠标左键按下时拖动,画布跟随拖动。 本篇和上一篇是同一系列,实现的原理是不同的,基本思想是画布本身不用缩放和平移,主要针对子元素进行变换,使用矩阵记忆和运算就挺方便的。代码主要来源:https://github.com/SEilers/WpfPanAndZoom
以下是控件的源码:
<Canvas x:Class="vkt.demo.canvas.mouse.CustomControls.ZoomCanvas"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:vkt.demo.canvas.mouse.CustomControls"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800" Background="LightGray">
</Canvas>
后台代码:
/// <summary>
/// ZoomCanvas.xaml 的交互逻辑
/// https://stackoverflow.com/questions/35165349/how-to-drag-rendertransform-with-mouse-in-wpf
/// </summary>
public partial class ZoomCanvas : Canvas
{
#region Variables
private readonly MatrixTransform _transform = new MatrixTransform();
private Point _initialMousePosition;
private bool _dragging;
private UIElement _selectedElement;
private Vector _draggingDelta;
private Color _lineColor = Color.FromArgb(0xFF, 0xF0, 0xF0, 0xF0);
private Color _backgroundColor = Color.FromArgb(0xFF, 0xE8, 0xE7, 0xE6);
private List<Line> _gridLines = new List<Line>();
#endregion
public ZoomCanvas()
{
InitializeComponent();
MouseDown += ZoomCanvas_MouseDown;
MouseUp += ZoomCanvas_MouseUp;
MouseMove += ZoomCanvas_MouseMove;
MouseWheel += ZoomCanvas_MouseWheel;
BackgroundColor = _backgroundColor;
// draw lines
//for (int x = -40000; x <= 40000; x += 10)
//{
// Line verticalLine = new Line
// {
// Stroke = new SolidColorBrush(_lineColor),
// X1 = x,
// Y1 = -40000,
// X2 = x,
// Y2 = 40000
// };
// if (x % 1000 == 0)
// {
// verticalLine.StrokeThickness = 2;
// }
// else
// {
// verticalLine.StrokeThickness = 1;
// }
// Children.Add(verticalLine);
// _gridLines.Add(verticalLine);
//}
//for (int y = -40000; y <= 40000; y += 10)
//{
// Line horizontalLine = new Line
// {
// Stroke = new SolidColorBrush(_lineColor),
// X1 = -40000,
// Y1 = y,
// X2 = 40000,
// Y2 = y
// };
// if (y % 1000 == 0)
// {
// horizontalLine.StrokeThickness = 2;
// }
// else
// {
// horizontalLine.StrokeThickness = 1;
// }
// Children.Add(horizontalLine);
// _gridLines.Add(horizontalLine);
//}
}
public float Zoomfactor { get; set; } = 1.1f;
public Color LineColor
{
get { return _lineColor; }
set
{
_lineColor = value;
foreach (Line line in _gridLines)
{
line.Stroke = new SolidColorBrush(_lineColor);
}
}
}
public Color BackgroundColor
{
get { return _backgroundColor; }
set
{
_backgroundColor = value;
Background = new SolidColorBrush(_backgroundColor);
}
}
public void SetGridVisibility(Visibility value)
{
foreach (Line line in _gridLines)
{
line.Visibility = value;
}
}
private void ZoomCanvas_MouseDown(object sender, MouseButtonEventArgs e)
{
if (e.ChangedButton == MouseButton.Right)
{
if (this.Children.Contains((UIElement)e.Source))
{
_selectedElement = (UIElement)e.Source;
Point mousePosition = Mouse.GetPosition(this);
double x = Canvas.GetLeft(_selectedElement);
double y = Canvas.GetTop(_selectedElement);
Point elementPosition = new Point(x, y);
_draggingDelta = elementPosition - mousePosition;
}
_dragging = true;
}
else if (e.ChangedButton == MouseButton.Left)
{
_initialMousePosition = _transform.Inverse.Transform(e.GetPosition(this));
}
}
private void ZoomCanvas_MouseUp(object sender, MouseButtonEventArgs e)
{
_dragging = false;
_selectedElement = null;
}
private void ZoomCanvas_MouseMove(object sender, MouseEventArgs e)
{
//if (_dragging && e.RightButton == MouseButtonState.Pressed)
//{
// double x = Mouse.GetPosition(this).X;
// double y = Mouse.GetPosition(this).Y;
// if (_selectedElement != null)
// {
// SetLeft(_selectedElement, x + _draggingDelta.X);
// SetTop(_selectedElement, y + _draggingDelta.Y);
// }
//}
if (e.LeftButton == MouseButtonState.Pressed)
{
Point mousePosition = _transform.Inverse.Transform(e.GetPosition(this));
Vector delta = Point.Subtract(mousePosition, _initialMousePosition);
var translate = new TranslateTransform(delta.X, delta.Y);
_transform.Matrix = translate.Value * _transform.Matrix;
foreach (UIElement child in this.Children)
{
child.RenderTransform = _transform;
}
}
}
private void ZoomCanvas_MouseWheel(object sender, MouseWheelEventArgs e)
{
float scaleFactor = Zoomfactor;
if (e.Delta < 0)
{
scaleFactor = 1f / scaleFactor;
}
Point mousePostion = e.GetPosition(this);
Matrix scaleMatrix = _transform.Matrix;
scaleMatrix.ScaleAt(scaleFactor, scaleFactor, mousePostion.X, mousePostion.Y);
_transform.Matrix = scaleMatrix;
foreach (UIElement child in this.Children)
{
double x = GetLeft(child);
double y = GetTop(child);
double sx = x * scaleFactor;
double sy = y * scaleFactor;
SetLeft(child, sx);
SetTop(child, sy);
child.RenderTransform = _transform;
}
}
}
提示:画太多线会有性能问题,但正常使用场景不受影响。
使用过程:
<Grid VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
<CustomControls:PanAndZoomCanvas x:Name="canvas" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" />
</Grid>
源码下载:链接:https://pan.baidu.com/s/1V6cL7boUMQ1G23VG3KtD-Q
关注我的微信公众号
在公众号里留言交流
投稿邮箱:1052839972@qq.com
庭院深深深几许?杨柳堆烟,帘幕无重数。
玉勒雕鞍游冶处,楼高不见章台路。
雨横风狂三月暮。门掩黄昏,无计留春住。
泪眼问花花不语,乱红飞过秋千去。
如果感觉对您有帮助
欢迎向作者提供捐赠
这将是创作的最大动力