2021-11-06 乐帮网
wpf
首先说明示例代码的环境:.Net Core WPF + Net 5(.Net Core 3 同样适用) 最后会提供源码下载。
实现的基本功能:使用鼠标左键按下时拖动,画布跟随拖动。 实现缩放,但是是通过右侧的按钮来控制缩放的中心点和缩放的比例(1为原始大小)
为什么我没有实现通过鼠标滚轮来缩放呢?这个并不是我没有尝试,只是发现存在一定问题,主要是缩放中心点的问题在MouseOver过程中并不稳定,体验并不好。所以就放弃了,想要完美实现请查看我的下一篇文章。
实现的主要逻辑:通过定义两个Transform分别负责平移和缩放。这里没有从零开始写,直接使用了别人的代码见:https://github.com/mdrabick/StiZoomableCanvas
我猜你一定很想知道遇到什么问题,其实还是缩放过程中中心点计算并不稳定。
以下是我的源码:
<Grid x:Name="grid">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width="200"></ColumnDefinition>
</Grid.ColumnDefinitions>
<StackPanel Grid.Row="0" Grid.Column="1" Background="LightSlateGray">
<StackPanel.Resources>
<Style TargetType="{x:Type FrameworkElement}">
<Setter Property="Margin" Value="0,10,0,0"/>
</Style>
<Style TargetType="{x:Type Label}" BasedOn="{StaticResource {x:Type FrameworkElement}}" />
<Style TargetType="{x:Type TextBox}" BasedOn="{StaticResource {x:Type FrameworkElement}}" />
<Style TargetType="{x:Type Button}" BasedOn="{StaticResource {x:Type FrameworkElement}}" />
</StackPanel.Resources>
<Label>在这里设置中心点</Label>
<TextBox x:Name="centerXInput" Text="400"/>
<TextBox x:Name="centerYInput" Text="400"/>
<TextBox x:Name="scaleInput" Text="1.2"/>
<Button Click="Button_Click" Content="点击缩放"></Button>
</StackPanel>
<ScrollViewer Name="scroll" Grid.Row="0" Grid.Column="0" HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Hidden" >
<Controls:StiZoomableCanvas Margin="0" Loaded="CanvasLoaded" x:Name="zoomCanvas" ApplyTransform="True" >
<Rectangle Width="40000" Height="40000" Fill="LightGray" Canvas.Left="-2000" Canvas.Top="-2000" />
<Ellipse Canvas.Left="-5" Canvas.Top="-5" Fill="Red" Width="10" Height="10"/>
<Ellipse Canvas.Left="500" Canvas.Top="200" Fill="Purple" Width="100" Height="100"/>
<Rectangle Width="300" Height="500" Fill="Gold" Canvas.Top="100" Canvas.Left="100"></Rectangle>
</Controls:StiZoomableCanvas>
</ScrollViewer>
</Grid>
后台代码:
public partial class MainWindow : Window
{
private Point _mouseOverPoint;
private Point _mouseDownPoint;
private Point _canvasPoint;
public MainWindow()
{
InitializeComponent();
zoomCanvas.AddHandler(Button.MouseLeftButtonDownEvent, new MouseButtonEventHandler(CanvasMouseLeftButtonDown), true);
zoomCanvas.AddHandler(Button.MouseMoveEvent, new MouseEventHandler(CanvasMouseMove), true);
zoomCanvas.AddHandler(Button.MouseLeftButtonUpEvent, new MouseButtonEventHandler(CanvasMouseLeftButtonUp), true);
}
private void Button_Click(object sender, RoutedEventArgs e)
{
var group = zoomCanvas.TransformGroup;
double scale = 1, centerX, centerY;
double.TryParse(scaleInput.Text, out scale);
double.TryParse(centerXInput.Text, out centerX);
double.TryParse(centerYInput.Text, out centerY);
ScaleTransform transform = group.Children[0] as ScaleTransform;
transform.CenterX = centerX;
transform.CenterY = centerY;
zoomCanvas.Scale = scale;
//zoomCanvas.Offset = new Point(zoomCanvas.Width / 2, zoomCanvas.Height / 2);
}
private void CanvasMouseMove(object sender, MouseEventArgs e)
{
StiZoomableCanvas canvas = sender as StiZoomableCanvas;
//_mouseOverPoint = e.GetPosition(canvas);
if (e.LeftButton == MouseButtonState.Pressed)
{
Point point = e.GetPosition(grid);
double dx = _mouseDownPoint.X + point.X - _canvasPoint.X;
double dy = _mouseDownPoint.Y + point.Y - _canvasPoint.Y;
//canvas.Margin = new Thickness(dx, dy, 0, 0);
canvas.Offset = new Point(-dx, -dy);
}
}
private void CanvasMouseWheel(object sender, MouseWheelEventArgs e)
{
StiZoomableCanvas canvas = sender as StiZoomableCanvas;
double scale = canvas.Scale;
if (e.Delta > 0)
scale += Math.Abs(scale) * 0.03;
else
scale -= Math.Abs(scale) * 0.03;
if (scale < 0.2)
return;
//var group = canvas.TransformGroup;
//Point pointToContent = group.Inverse.Transform(_mouseOverPoint);
//Debug.Assert(group != null, "hello current control");
//ScaleTransform transform = group.Children[0] as ScaleTransform;
//if (transform.ScaleX + scale < 0.2)
//{
// return;
//}
//transform.ScaleX += scale;
//transform.ScaleY += scale;
//TranslateTransform transform1 = group.Children[1] as TranslateTransform;
//transform1.X = -1 * ((pointToContent.X * transform.ScaleX) - _mouseOverPoint.X);
//transform1.Y = -1 * ((pointToContent.Y * transform.ScaleY) - _mouseOverPoint.Y);
}
private void CanvasMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
StiZoomableCanvas canvas = sender as StiZoomableCanvas;
if (canvas != null)
{
_mouseDownPoint = new Point()
{
X = -canvas.Offset.X,
Y = -canvas.Offset.Y
};
_canvasPoint = e.GetPosition(grid);
canvas.CaptureMouse();
canvas.Cursor = Cursors.SizeAll;
}
}
private void CanvasMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
StiZoomableCanvas canvas = sender as StiZoomableCanvas;
canvas.ReleaseMouseCapture();
canvas.Cursor = Cursors.Arrow;
}
private void CanvasLoaded(object sender, RoutedEventArgs e)
{
}
}
源码地址:链接:https://pan.baidu.com/s/172TE8tn1bBFzUyIz8wt9bA
关注我的微信公众号
在公众号里留言交流
投稿邮箱:1052839972@qq.com
庭院深深深几许?杨柳堆烟,帘幕无重数。
玉勒雕鞍游冶处,楼高不见章台路。
雨横风狂三月暮。门掩黄昏,无计留春住。
泪眼问花花不语,乱红飞过秋千去。
如果感觉对您有帮助
欢迎向作者提供捐赠
这将是创作的最大动力