2011-04-01 109 views
0

我需要放大和缩小画布。但变焦应始终以画面中心(不是画布)为中心。这不符合我目前的代码!它始终放大到画布的中心,而不是当前屏幕。 画布也应该是可移动的,但不应该被允许远离它的边界。 这是我到目前为止有:放大和缩小到画布中的视口中心

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但出于某种原因,这是更好的性能..不要问我为什么!

有人可以帮我吗?

+0

这种性能更高的原因是您实际上并没有缩放。你改变画布的大小是不同的,因为如果我没有弄错的话,这将不会影响画布的孩子的大小。 – 2011-04-02 01:52:39

+0

我假设是正确的,你有这个Grid + Canvas里面的ViewBox?该视框本身正在使用ScaleTransform。您可能想尝试跳过视图框并直接使用ScaleTransform – 2011-04-05 20:09:32

回答

1

这是我的平移和缩放解决方案,在我的复杂应用程序(12000px x 12000px)中都能正常工作。

你需要有一个变焦依赖属性(双)和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; 
    } 

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

如果您需要更多信息(我知道这个问题很旧,这就是为什么我没有详细说明所有事情)请告诉我。