2

When zooming in on a drawing on a Canvas I have the requirement to show scrollbars.
The Canvas is in a ScrollViewer and I increase the Width/Height of the Canvas so that that the scollbars appear (otherwise they don't).

To zoom in with a factor of 1.1 I use this code:

Matrix m = this.LayoutTransform.Value;
if (e.Delta > 0) f = 1.1;
else f = 1.0 / 1.1;
m.Scale(f, f);
this.LayoutTransform = new MatrixTransform(m);
this.Height = this.ActualHeight * f;
this.Width = this.ActualWidth * f;

It turns out that the Canvas becomes much too large. The drawing zooms in 10% but the width seems to become 20% more like the square of 1.1. So I use Math.Sqrt(f); instead of f.

Can anybody explain why it behaves this way?

Gerard
  • 13,023
  • 14
  • 72
  • 125
  • You seem to apply the scaling factor twice, first by the LayoutTransform and second by multiplying Width and Height. You should do only one of these, preferably only the LayoutTransform. – Clemens Mar 04 '14 at 11:39
  • Then the scrollbars do not appear (which is a requirement). – Gerard Mar 04 '14 at 11:47

1 Answers1

1

You should only change the LayoutTransform of the Canvas, like in this simplified example:

<ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
    <Canvas Width="1000" Height="1000" Background="Transparent"
            MouseWheel="Canvas_MouseWheel">
        <Canvas.LayoutTransform>
            <MatrixTransform/>
        </Canvas.LayoutTransform>
    </Canvas>
</ScrollViewer>

The MouseWheel event handler:

private void Canvas_MouseWheel(object sender, MouseWheelEventArgs e)
{
    var element = (FrameworkElement)sender;
    var transform = (MatrixTransform)element.LayoutTransform;
    var matrix = transform.Matrix;
    var scale = e.Delta >= 0d ? 1.1 : (1d / 1.1);

    matrix.Scale(scale, scale);
    transform.Matrix = matrix;

    e.Handled = true;
}
Clemens
  • 123,504
  • 12
  • 155
  • 268
  • Does it work without `Width="1000" Height="1000"`? My Canvas has no initial size, it fits to its parent size and the drawing dimensions too. – Gerard Mar 04 '14 at 11:54
  • It has to have an initial size, otherwise the ScrollViewer doesn't make sense. You may however set the initial size in code behind as soon as it is available. – Clemens Mar 04 '14 at 11:57
  • One more question: when I reset the Transform back to Identity, the scrollbars remain visible, while initially they are not visible (which is good) and the Canvas size hasn't changed. – Gerard Mar 04 '14 at 13:07
  • One more question: when using RenderTransform instead of LayoutTransform the scollbars do not appear despite setting Width&Heigth. – Gerard Mar 04 '14 at 13:20
  • 1
    First question: hard to tell without seeing your code. Second: RenderTransform does not influence layout, but you need that. You can't use RenderTransform here. – Clemens Mar 04 '14 at 17:28
  • Is it possible perhaps to combine Render- and LayoutTransform, because the RenderTransform zooms much more nicely. – Gerard Mar 04 '14 at 18:22
  • I don't think so. As said before, you need the layout to be recalculated in order to update the scrollbars. – Clemens Mar 04 '14 at 18:44