缩放和平移WPF画布

时间:2015-03-03 15:03:40

标签: wpf wpf-controls zoom

我对WPF有疑问。

我有一个Canvas作为可视化编辑器!我有几个节点'使用' X'定位在画布中和' Y'属性(Canvas.Left和Canvas.Top)。现在,我需要这个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;
        }
    }

&#39;节点&#39;是我在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;
    }

所以,在平移&#39;我计算到最后一个鼠标位置的差异,并使用该向量来操纵节点,而不是Canvas本身。 当我缩放时,我确定新的缩放,设置新的RenderTransform,调整画布大小以再次填充提供的空间,然后再次重新定位画布中的节点。

现在效果很好。我可以&amp; amp; amp;变焦&#39;围绕着我的想法,但我意识到,在我的网络中存在许多节点&#39; (连接的节点),事情变得非常缓慢。

一个原因是,在节点的每次移动中都会引发一些事件,从而导致平移时出现明显的延迟。

如何以高效的方式实现这样的事情(没有固定的Canvas-size和Scrollbars)?我有可以使用的控件吗?使用Extended WPF工具包的ZoomBox控件可以实现这一点吗?

谢谢!

1 个答案:

答案 0 :(得分:0)

我已经为此功能编写了一个Viewport控件。

我也将其打包在nuget

PM > Install-Package Han.Wpf.ViewportControl

它扩展了ContentControl,其中可以包含任何FrameworkElement,并提供受约束的缩放和平移功能。只需确保将Generic.xaml添加到您的app.xaml

<Application.Resources>

    <ResourceDictionary Source="pack://application:,,,/Han.Wpf.ViewportControl;component/Themes/Generic.xaml" />

</Application.Resources>

用法:

<Grid width="1200" height="1200">

    <Button />

</Grid>

控件和主题的源代码在我的gist上,并且可以在我的github上找到,以及将图像加载到视口控件中的演示应用程序。