首页 文章

缩放和平移WPF画布

提问于
浏览
0

我对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 回答

  • 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上找到,还有一个将图像加载到视口控件中的演示应用程序 .

相关问题