Вот мое решение для Pan и Zoom, оба отлично работают в моем сложном приложении (12000px x 12000px).
Вам необходимо иметь свойство зависимостей Zoom (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();
}
}
}
Когда вы обновляете Zoom, вы вызываете этот метод для вычисления центральной точки:
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;
}
Я не предоставляю весь код, но это основа, если вы понимаете, что я написал.
Если вам нужна дополнительная информация (я знаю, что этот вопрос старый, вот почему я не все подробно), дайте мне знать.