0

I have some issue to zoom on an image which is in a canvas. I was thinking about using matrixtransform but it doesn't work. It returns me an exception that I don't understand! Here is the XAML:

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="40"/>
        <RowDefinition Height="*"/>
    </Grid.RowDefinitions>
    <Button Click="Button_Click"/>

    <ScrollViewer Grid.Row="2"
                  Name="scroll"
                  HorizontalScrollBarVisibility="Auto" 
                  VerticalScrollBarVisibility="Auto">

        <Canvas Name="Container"
                ClipToBounds="True"
                MouseWheel="Container_MouseWheel"
               >

            <Image  Name="ImageSource"
                >
                <Image.LayoutTransform>
                    <MatrixTransform/>
                </Image.LayoutTransform>
            </Image>
        </Canvas>
    </ScrollViewer>
</Grid>

The code behind:

private void Button_Click(object sender, RoutedEventArgs e)
{
    Bitmap Bmp = new Bitmap(@"C:\Desktop\image1.bmp");
    ImageSource.Source = CreateBitmapSourceFromGdiBitmap(Bmp);
    Container.Width = Bmp.Width;
    Container.Height = Bmp.Height;
}

private void Container_MouseWheel(object sender, MouseWheelEventArgs e)
{
    var element = sender as UIElement;
    var position = e.GetPosition(element);
    var transform = element.RenderTransform as MatrixTransform;
    var matrix = transform.Matrix;
    var scale = e.Delta >= 0 ? 1.1 : (1.0 / 1.1); // choose appropriate scaling factor

    matrix.ScaleAtPrepend(scale, scale, position.X, position.Y);
    transform.Matrix = matrix;
}

If someone could give me a hint that would be nice, thanks!

Json
  • 153
  • 2
  • 7
  • 17

3 Answers3

2

Replace

transform.Matrix = matrix;

with

element.RenderTransform = new MatrixTransform( matrix );

and it works ;)

SnowballTwo
  • 529
  • 2
  • 11
  • @ SnowballTwo i still have a problem with the scrollviewer, the size or the scroll doesn,'t resize according to the zoom :/ – Json Dec 17 '15 at 10:16
  • You should get rid of your container, set the image as first child of the scrollviewer, set the images width and height matching the imagesource initially and use a LayoutTransform instead of a RenderTransform. Not tested... – SnowballTwo Dec 17 '15 at 10:19
  • i can't find how to use layout transform with matrix transform in the coe behind. if you could gibe me an hint ;) thx ! – Json Dec 17 '15 at 12:02
  • Simply replace all RenderTransforms with LayoutTransforms... they are both of type "Transform"... you may press ctrl + shift + f and search all usages in your project – SnowballTwo Dec 17 '15 at 12:22
1

I do not know if you solved this yet. But the Xaml code here will let you zoom nicely. It works and you use the scroll bars of the ScrollVider to pan the image.

<ScrollViewer x:Name="vbxImageViewBox" 
              CanContentScroll="False" 
              HorizontalScrollBarVisibility="Auto"
              VerticalScrollBarVisibility="Auto">

    <Grid x:Name="grdItcMain" Margin="5">
         <Grid.LayoutTransform>
            <TransformGroup>
                <ScaleTransform 
                    ScaleX="{Binding Path=ScaleFactor, 
                             ElementName=this, 
                             Mode=OneWay}" 
                    ScaleY="{Binding Path=ScaleFactor, 
                             ElementName=this, 
                             Mode=OneWay}" />
            </TransformGroup>
        </Grid.LayoutTransform>
        <Rectangle Fill="DeepSkyBlue" Stretch="Fill" />
        <Image MouseWheel="Image_MouseWheel"
            Source="{Binding PreviewSource,
                     ElementName=this,
                     Mode=OneWay}"
            Stretch="Fill" />
    </Grid>
</ScrollViewer>

private const double _smallChange = 0.1;
private double _scaleFactor;
public double ScaleFactor 
{ 
    get 
    { 
        return _scaleFactor; 
    } 
    set 
    { 
        _scaleFactor = value; 
        OnPropertyChanged("ScaleFactor"); 
    } 
}

private void Window_Loaded(object sender, RoutedEventArgs e)
{
     double scaleX = (grdItcMain.ActualWidth - 20) / 1920;
     double scaleY = (grdItcMain.ActualHeight - 20) / 1080;
     double dScale = Math.Min(scaleX, scaleY);
     ScaleFactor = dScale; //size to fit initially
}

private void Image_MouseWheel(object sender, MouseWheelEventArgs e)
{
    if (e.Delta > 0)
    {
        if ((ScaleFactor + _smallChange) > 25.0)
        {
            return;
        }

        ScaleFactor += _smallChange;

        vbxImageViewBox.LineRight();
        vbxImageViewBox.LineRight();
        vbxImageViewBox.LineRight();
        vbxImageViewBox.LineRight();
        vbxImageViewBox.LineRight();

        vbxImageViewBox.LineDown();
        vbxImageViewBox.LineDown();
        vbxImageViewBox.LineDown();
        vbxImageViewBox.LineDown();
        vbxImageViewBox.LineDown();
        vbxImageViewBox.LineDown();
    }
    else
    {
        if ((ScaleFactor - _smallChange) < 0.001)
        {
            return;
        }
        ScaleFactor -= _smallChange;

        vbxImageViewBox.LineLeft();
        vbxImageViewBox.LineLeft();
        vbxImageViewBox.LineLeft();
        vbxImageViewBox.LineLeft();
        vbxImageViewBox.LineLeft();

        vbxImageViewBox.LineUp();
        vbxImageViewBox.LineUp();
        vbxImageViewBox.LineUp();
        vbxImageViewBox.LineUp();
        vbxImageViewBox.LineUp();
        vbxImageViewBox.LineUp();
        }
    }

This is not a perfect solution but it works and is easy to implement.

Doug

AeroClassics
  • 1,074
  • 9
  • 19
0

Anybody else looking for solutions to this should try the excellent solution here created by Wiesław Šoltés. Just paste in the code shown in the answer.

TripleAntigen
  • 2,221
  • 1
  • 31
  • 44