我对WPF有疑问 .
我有一个Canvas作为可视化编辑器!我使用'X'和'Y'属性(Canvas.Left和Canvas.Top)在Canvas中放置了一些“节点” . 现在,我需要这个Canvas让用户放大(进出)和Pan,就像他想要的那样 .
我实现了一种黑客来模仿这种行为 . 这是让用户在Canvas中'pan'的代码:
///In file MainWindow.xaml.cs
private void ZoomPanCanvas_MouseMove(object sender, MouseEventArgs e) {
if (IsMouseDown) {
///Change the Cursor to Scroll
if (mNetworkUI.Cursor != Cursors.ScrollAll)
mNetworkUI.Cursor = Cursors.ScrollAll;
var currPosition = e.GetPosition(mNetworkUI);
var diff = currPosition - MouseLastPosition;
var p = new Point(diff.X, diff.Y);
mNetworkUI.ViewModel.Network.SetTransformOffset(p);
MouseLastPosition = currPosition;
}
}
///In file NetworkViewModel.cs
public void SetTransformOffset(Point newOffset) {
for (int i = 0; i < Nodes.Count; i++) {
Nodes[i].X += newOffset.X;
Nodes[i].Y += newOffset.Y;
}
}
“节点”是我在Canvas中显示的编辑器节点 . 缩放(关于鼠标位置的工作原理如下:
///File MainWindow.xaml.cs
private void ZoomPanCanvas_MouseWheel(object sender, MouseWheelEventArgs e) {
///Determine the Scaling Factor and Scale the Rule-Editor
var factor = (e.Delta > 0) ? (1.1) : (1 / 1.1);
currrentScale = factor * currrentScale;
ScaleNetwork();
///Translate the Nodes to the desired Positions
var pos = e.GetPosition(mNetworkUI);
var transform = new ScaleTransform(factor, factor, pos.X, pos.Y);
var offSet = new Point(transform.Value.OffsetX, transform.Value.OffsetY);
mNetworkUI.ViewModel.Network.SetTransformOffset(offSet);
}
///Also in MainWindow.xaml.cs
private void ScaleNetwork() {
mNetworkUI.RenderTransform = new ScaleTransform(currrentScale, currrentScale);
mNetworkUI.Width = ZoomPanCanvas.ActualWidth / currrentScale;
mNetworkUI.Height = ZoomPanCanvas.ActualHeight / currrentScale;
}
因此,在“平移”中,我计算与最后一个鼠标位置的差异,并使用该向量来操纵节点,而不是Canvas本身 . 当我缩放时,我确定新的缩放,设置新的RenderTransform,调整画布大小以再次填充提供的空间,并再次重新定位画布中的节点 .
它现在非常好用 . 我可以“平移和缩放”我想要的方式,但我意识到,由于我的“网络”(连接节点)中存在许多节点,因此事情变得非常缓慢 .
一个原因是,在节点的每次移动中,一些事件被提升,导致平移时显着的延迟 .
这样的事情(没有固定的Canvas-size和Scrollbars)如何以高效的方式实现?我有可以使用的控件吗?这是否可以使用Extended WPF工具包的ZoomBox控件?
谢谢!
1 回答
我已经为这个确切的功能编写了一个Viewport控件 .
我也把它打包在nuget
它扩展了
ContentControl
,它可以包含任何FrameworkElement
并提供约束缩放和平移功能 . 只需确保将Generic.xaml
添加到您的app.xaml
用法:
控件和主题的源代码在我的gist上,可以在我的github上找到,还有一个将图像加载到视口控件中的演示应用程序 .