如何根据缩放级别在WPF画布上设置平移限制? [英] How to set panning limits on WPF Canvas based on zoom level?
问题描述
我正在尝试在此处找到的控件上设置缩放和平移限制:
实际行为:对象/红色正方形边缘脱离当前视图(仍然有限制,但设置不正确).
代码说明
所有操作都在
- 平移限制:
MinTranslateX,MaxTranslateX;MinTranslateY,MaxTranslateY
- 当前平移:
TranslateX,TranslateY
- 当前缩放:
Zoom
- 缩放量已更改:
deltaZoom
(局部变量) -
Zoom_PropertyChanged
方法 -
LimitZoomingAndPanning
方法
我尝试过的
在 LimitZoomingAndPanning
方法中,我设置了适用于 Zoom == 1
( deltaZoom == 1
)的转换/平移限制,但为其他 Zoom
值给出了错误的限制:
MinTranslateX = box.BottomLeft.X * deltaZoom;MinTranslateY = box.BottomLeft.Y * deltaZoom;MaxTranslateX = ActualWidth-box.Size.Width * deltaZoom;MaxTranslateY = ActualHeight-box.Size.Height * deltaZoom;
box
变量实际上是画布内对象的边界框. ActualWidth
和 ActualHeight
是在其上渲染对象的画布的大小.
从逻辑上讲,所有转换/平移限制都应取决于 deltaZoom
.
也许我遗漏了一些东西?
我最初尝试使用 ZoomAndPanControl
做同样的事情,但是无法实现我想要的效果,所以我最终写了我的自己的控件来提供受约束的缩放和平移控件.
我将此控件打包在 nuget 上,但是可以在我的要点和我的 并将主题添加到 我知道您没有使用MatrixTransform,而是将控件约束到父对象的边界,其计算方式如下: 在Invalidate调用中 I'm trying to set zooming and panning limits on a control I found here:
https://wpfextensions.codeplex.com I managed to set zooming limits, but now I'm having trouble setting the panning limits so that you can't pan the object inside the canvas, outside the view. I succeeded in setting the limits, but only when the zoom level is 1 ( In order to set them correctly I have to take into consideration the I have created a simple, standalone project where I can reproduce the issue:
https://github.com/igorpopovio/CanvasZoomPan The project shows a desktop window with the Expected behaviour: object/red square edge cannot get out of the current view. Actual behaviour: object/red square edge gets out of the current view (still has limits, but aren't correctly set). All the action happens in this file and the important bits are: In the The Logically, all the translation/panning limits should depend on Maybe I'm missing something? I originally tried doing the same thing with the I have packaged this control up on nuget but it can be found on my gist and on my github with a demo project loading an image into the viewport control. Usage: and add the theme to the I know your not using the MatrixTransform but to constrain the control to the bounds of the parent is calculated like below: In the Invalidate call
这篇关于如何根据缩放级别在WPF画布上设置平移限制?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋! app.xaml
:
< Application.Resources>< ResourceDictionary Source ="pack://application:,,,//Han.Wpf.ViewportControl; component/Themes/Generic.xaml"/></Application.Resources>
私有无效OnMouseWheel(对象发送者,MouseWheelEventArgs e){如果(IsEnabled){var scale = e.Delta>0?ZoomSpeed:1/ZoomSpeed;var position = e.GetPosition(_content);var x = Constrain(scale,MinZoom/_matrix.M11,MaxZoom/_matrix.M11);var y = Constrain(scale,MinZoom/_matrix.M22,MaxZoom/_matrix.M22);_matrix.ScaleAtPrepend(x,y,position.X,position.Y);ZoomX = _matrix.M11;ZoomY = _matrix.M22;Invalidate();}}私有无效OnMouseMove(对象发送者,MouseEventArgs e){如果(IsEnabled& _capture){var position = e.GetPosition(this);var point = new Point{X =位置X-_origin.X,Y =位置Y-_origin.Y};var delta =点;_origin =位置;_matrix.Translate(delta.X,delta.Y);Invalidate();}}
Constrain()
私人double约束(double值,double min,double max){如果(min> max){最小值=最大值;}如果(值< =分钟){返回最小值;}如果(值> =最大值){返回最大值}返回值;}私有void Constrain(){var x = Constrain(_matrix.OffsetX,_content.ActualWidth-_content.ActualWidth * _matrix.M11,0);var y = Constrain(_matrix.OffsetY,_content.ActualHeight-_content.ActualHeight * _matrix.M22,0);_matrix = new Matrix(_matrix.M11,0d,0d,_matrix.M22,x,y);}
Zoom == 1
, so no zoom), but the moment you increase the zoom (by rotating the mouse wheel) things start to go wrong: the limits are set, but they are not set correctly.deltaZoom
(the amount zoom changed compared to the previous zoom value).Small demo project
ZoomControl
(canvas with ScaleTransform
, TranslateTransform
and a bunch of dependency properties to make it easier to work with the transforms). The ZoomControl
contains a red square and the window contains the ZoomControl
and a debug list of properties so I can see live how they change based on left click drag and mouse wheel zoom.Expected vs actual behaviour
Code explanations
MinTranslateX, MaxTranslateX; MinTranslateY, MaxTranslateY
TranslateX, TranslateY
Zoom
deltaZoom
(local variable) Zoom_PropertyChanged
method LimitZoomingAndPanning
method What I tried
LimitZoomingAndPanning
method I set the translation/panning limits which are working for Zoom == 1
(deltaZoom == 1
), but are giving incorrect limits for any other Zoom
values:MinTranslateX = box.BottomLeft.X * deltaZoom;
MinTranslateY = box.BottomLeft.Y * deltaZoom;
MaxTranslateX = ActualWidth - box.Size.Width * deltaZoom;
MaxTranslateY = ActualHeight - box.Size.Height * deltaZoom;
box
variable is actually the bounding box of the object inside the canvas. ActualWidth
and ActualHeight
are the size of the canvas on which the object is rendered.deltaZoom
.ZoomAndPanControl
but wasn't able to achieve what I wanted so I ended up writing my own control to provide a constrained zoom and pan control.PM > Install-Package Han.Wpf.ViewportControl
<controls:Viewport MinZoom="1" MaxZoom="50" ZoomSpeed="1.1">
<Grid width="1200" height="1200">
<Button />
</Grid>
</controls:Viewport
app.xaml
:<Application.Resources>
<ResourceDictionary Source="pack://application:,,,/Han.Wpf.ViewportControl;component/Themes/Generic.xaml" />
</Application.Resources>
private void OnMouseWheel(object sender, MouseWheelEventArgs e)
{
if (IsEnabled)
{
var scale = e.Delta > 0 ? ZoomSpeed : 1 / ZoomSpeed;
var position = e.GetPosition(_content);
var x = Constrain(scale, MinZoom / _matrix.M11, MaxZoom / _matrix.M11);
var y = Constrain(scale, MinZoom / _matrix.M22, MaxZoom / _matrix.M22);
_matrix.ScaleAtPrepend(x, y, position.X, position.Y);
ZoomX = _matrix.M11;
ZoomY = _matrix.M22;
Invalidate();
}
}
private void OnMouseMove(object sender, MouseEventArgs e)
{
if (IsEnabled && _capture)
{
var position = e.GetPosition(this);
var point = new Point
{
X = position.X - _origin.X,
Y = position.Y - _origin.Y
};
var delta = point;
_origin = position;
_matrix.Translate(delta.X, delta.Y);
Invalidate();
}
}
Constrain()
private double Constrain(double value, double min, double max)
{
if (min > max)
{
min = max;
}
if (value <= min)
{
return min;
}
if (value >= max)
{
return max;
}
return value;
}
private void Constrain()
{
var x = Constrain(_matrix.OffsetX, _content.ActualWidth - _content.ActualWidth * _matrix.M11, 0);
var y = Constrain(_matrix.OffsetY, _content.ActualHeight - _content.ActualHeight * _matrix.M22, 0);
_matrix = new Matrix(_matrix.M11, 0d, 0d, _matrix.M22, x, y);
}