在画布中放大和缩小视口的中心

时间:2011-04-01 14:10:38

标签: c# wpf wpf-controls zooming

我需要放大和缩小画布。但是缩放应始终以屏幕中心(而不是画布)为中心。这不适用于我目前的代码!它总是缩放到画布的中心而不是当前屏幕。 画布也应该是可移动的,但不应该被允许移离它的边界。 这就是我到目前为止所做的:

XAML

    <Grid>
    <Canvas HorizontalAlignment="Left" Name="canvas1" VerticalAlignment="Top">
    </Canvas>
</Grid>

C#

        // x & y arent the position, it's how many pixel the object should move to the left/right etc
    public void setPosition(double x, double y)
    {
        Thickness t = new Thickness(canvas1.Margin.Left + x, canvas1.Margin.Top + y, 0, 0);
        if (t.Left > 0)
        {
            t.Left = 0;
        }
        else if(t.Left < -(canvas1.Width - System.Windows.SystemParameters.PrimaryScreenWidth))
        {
            t.Left = -(canvas1.Width - System.Windows.SystemParameters.PrimaryScreenWidth);
        }

        if (t.Top > 0)
        {
            t.Top = 0;
        }
        else if (t.Top < -(canvas1.Height - System.Windows.SystemParameters.PrimaryScreenHeight))
        {
            t.Top = -(canvas1.Height - System.Windows.SystemParameters.PrimaryScreenHeight);
        }

        canvas1.Margin = t;
    }

    public void setZoom(double zoom)
    {
        double tempW = canvas1.Width;
        double tempH = canvas1.Height;

        canvas1.Width *= (1 + zoom);
        canvas1.Height *= (1 + zoom);

        Debug.WriteLine("tempW: " + tempW + " tempH: " + tempH + " canvas1.Width: " + canvas1.Width + " canvas1.Height: " + canvas1.Height);

        setPosition((tempW - canvas1.Width) / 2, ((tempH - canvas1.Height) / 2));
    }

是的,我知道像ScaleTransform这样的东西,但由于某种原因,这是更高效的..不要问我为什么!

有人能帮助我吗?

1 个答案:

答案 0 :(得分:2)

这是我的Pan和Zoom解决方案,在我的复杂应用程序(12000px x 12000px)中都可以正常工作。

您需要具有缩放依赖属性(double)和ScaleTransform属性

private double m_dCurZoom = 1.0;
public double Zoom
{
   get { return m_dCurZoom; }
   set
   {
      double oldzoom = m_dCurZoom;
      if (m_dCurZoom != value)
      {
         m_dCurZoom = value;
         OnPropertyChanged("Zoom");
         UpdateZoom(oldzoom);
      }
   }
}

private ScaleTransform m_transZoom;
public ScaleTransform TransZoom
{
   get { return m_transZoom; }
}

private TranslateTransform m_transPan;

/// <summary>
/// Gets or sets the Panning in X axis.
/// </summary>
public double PanX
{
   get { return m_transPan.X; }
   set
   {
      if (m_transPan.X != value)
      {
         m_transPan.X = value;
         ResizeElementContents();
      }
   }
}

  /// <summary>
  /// Gets or sets the Panning in Y axis.
  /// </summary>
  public double PanY
  {
     get { return m_transPan.Y; }
     set
     {
        if (m_transPan.Y != value)
        {
           m_transPan.Y = value;
           ResizeElementContents();
        }
     }
  }

更新缩放时,可以调用此方法计算中心点:

public void UpdateZoom(double oldzoom)
{
   // Are we visible?
   if (m_root == null)
      return;

   // Get parent of VirtualPanel
   FrameworkElement parent = GetRootParent();
   if (parent == null)
       return;

   // Center point of the window
   Point ptCenter = new Point(parent.RenderSize.Width / 2, parent.RenderSize.Height / 2);

   // Translate into canvas coordinates
   ptCenter = m_root.TranslatePoint(ptCenter, m_canvas);

   // Update the zoom
   m_transZoom.ScaleX = m_dCurZoom;
   m_transZoom.ScaleY = m_dCurZoom;
   m_transPan.X -= ptCenter.X * m_dCurZoom - ptCenter.X * oldzoom;
   m_transPan.Y -= ptCenter.Y * m_dCurZoom - ptCenter.Y * oldzoom;

   ResizeElementContents();

   OnPropertyChanged("Zoom");
}


/// <summary>
  /// Calculate the transform for given zoom & region-to-display for the given root's render-size
  /// </summary>
  public bool ResizeElementContents()
  {
     FrameworkElement parent = GetRootParent();
     if (parent == null || m_transPan == null)
        return false;

     // Calculate the total region of the root
     Rect? region = WtoHelper.CalcElementRect(Root);
     if (region == null || region.HasValue == false)
        return false;

     // Scale the region to get the actal size with the zoom transformation.
     double rgnWid = region.Value.Width * m_dCurZoom;
     double rgnHei = region.Value.Height * m_dCurZoom;

     // Image fits within our window width?
     if (parent.RenderSize.Width > rgnWid)
        m_transPan.X = (parent.RenderSize.Width - rgnWid) / 2;
     else
     {
        // Image needs to be resized
        if (m_transPan.X < -(rgnWid - parent.RenderSize.Width))
           m_transPan.X = -(rgnWid - parent.RenderSize.Width);
        else if (m_transPan.X > 0)
           m_transPan.X = 0;
     }

     // Image fits within our window height?
     if (parent.RenderSize.Height > rgnHei)
        m_transPan.Y = (parent.RenderSize.Height - rgnHei) / 2;
     else
     {
        // Image needs to be resized
        if (m_transPan.Y < -(rgnHei - parent.RenderSize.Height))
           m_transPan.Y = -(rgnHei - parent.RenderSize.Height);
        else if (m_transPan.Y > 0)
           m_transPan.Y = 0;
     }

     return true;
  }

我不提供所有代码,但如果你能理解我写的内容,它就是一个基础。

如果您需要更多信息(我知道这个问题已经过时了,这就是为什么我没有详细说明一切)请告诉我。