wpfcanvasscrollviewermatrix-transform

MatrixTransform in combination with Width/Height of a Canvas


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?


Solution

  • 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;
    }