2

I am building an image viewer.

I have created a functionality that when the user moves the slider, it changes the ZoomLevel property value. This subsequently zooms the image based on the value provided by the ZoomLevel property.

<Image 
    Name="image"
    Source="Sample1.jpg"
    Opacity="1" 
    VerticalAlignment="Center"
    HorizontalAlignment="Center"
    Stretch="None"
    RenderTransformOrigin="0.5,0.5" 
    RenderOptions.BitmapScalingMode="HighQuality">
    <Image.RenderTransform>
        <TransformGroup>
            <ScaleTransform 
                ScaleX="{Binding Path=ZoomLevel}" 
                ScaleY="{Binding Path=ZoomLevel}" />
            <TranslateTransform />
        </TransformGroup>
    </Image.RenderTransform>
</Image>

I wish to be able to animate the zooming with a DoubleAnimation. Animation is supposed to start from the current zoom level and then get to the zoom specified in the bound ZoomLevel property. It would be great if someone could provide some help in XAML. Thanks!

Mouse wheel code:

private void border_MouseWheel(object sender, MouseWheelEventArgs e)
{
    int delta;

    delta = e.Delta;
    zoom(delta);
}

private void zoom(int delta)
{
    double zoomIncrement;

    //Different zoom levels at different zoom stages
    if (ZoomLevel > 2)
    {
        zoomIncrement = Math.Sign(delta) * 0.2;
    }
    else if (ZoomLevel >= 1 && ZoomLevel <= 2)
    {
        zoomIncrement = Math.Sign(delta) * 0.1;
    }
    else
    {
        zoomIncrement = Math.Sign(delta) * 0.06;
    }

    //Rounding zoom level to boundary values
    //Zooming is allowed from 10% to 600%
    if (ZoomLevel + zoomIncrement > 6)
    {
        ZoomLevel = 6;
    }
    else if (ZoomLevel + zoomIncrement < 0.1)
    {
        ZoomLevel = 0.1;
    }
    else
    {
        ZoomLevel += zoomIncrement;
    }
}
H.B.
  • 166,899
  • 29
  • 327
  • 400
Boris
  • 9,986
  • 34
  • 110
  • 147
  • Are you binding directly to the slider value? If so, what effect are you looking for? What is happening now? – Scott Boettger Sep 15 '11 at 19:23
  • Moving the slider changes the value of the `Zoom` property. Scrolling also changes the value of the `Zoom` property. Right now, the `Zoom` property is bound to the `ScaleX` and `ScaleY` properties of the image's ScaleTransform. Each change made by the scroll wheel or slider results in +/- 0.2 zoom increment. – Boris Sep 15 '11 at 19:31
  • For example: if the zoom is currently set at 80% scrolling up will change the zoom level to 82%. I want to animate that change. – Boris Sep 15 '11 at 19:32
  • Do you have the IsSnapToTickEnabled set true on the slider? Removing that would make it look smoother. If that's not a viable option i'll work something up for you now. – Scott Boettger Sep 15 '11 at 19:35
  • `IsSnapToTickEnabled` is not set to `true`. Zooming with slider is smooth, but zooming with scroll wheel isn't, because there's a 2% jump for each wheel movement. Reducing the zoom increment would result in smoother zooming, but then I'd have to scroll like mad just to make a small zoom level change :) The best option, I think, would be to animate that zoom level change. What do you think Scott? – Boris Sep 15 '11 at 19:40
  • I agree with you. Do it have to be XAML side? You are able to create storyboards with in C#? – Scott Boettger Sep 15 '11 at 19:42
  • It doesn't have to be XAML side, I just prefer that way. If you can help me with C# code-behind, I'd appreciate it very much :) – Boris Sep 15 '11 at 19:45
  • would you be able to post your mousewheel code? – Scott Boettger Sep 15 '11 at 19:54

2 Answers2

2

It is a little messy but try this.

namespace Zoom
{

    public partial class Window1
    {   
        public double ZoomLevel { get; set; }
        public double SlideLevel { get; set; }

        public Window1()
        {
            InitializeComponent();

            ZoomLevel = 1.0;
            SlideLevel = 1.0;
            image.MouseWheel += image_MouseWheel;

        }

        private void image_MouseWheel(object sender, MouseWheelEventArgs e)
        {
            double zoom = e.Delta > 0 ? .1 : -.1;
            slider.Value = (SlideLevel + zoom);
        }

        private void ZoomImage(double zoom)
        {
            Storyboard storyboardh = new Storyboard();
            Storyboard storyboardv = new Storyboard();

            ScaleTransform scale = new ScaleTransform(ZoomLevel, ZoomLevel);
            image.RenderTransformOrigin = new Point(0.5, 0.5);
            image.RenderTransform = scale;

            double startNum = ZoomLevel;
            double endNum = (ZoomLevel += zoom);

            if (endNum > 1.0)
            {
                endNum = 1.0;
                ZoomLevel = 1.0;
            }

            DoubleAnimation growAnimation = new DoubleAnimation();
            growAnimation.Duration = TimeSpan.FromMilliseconds(300);
            growAnimation.From = startNum;
            growAnimation.To = endNum;
            storyboardh.Children.Add(growAnimation);
            storyboardv.Children.Add(growAnimation);

            Storyboard.SetTargetProperty(growAnimation, new PropertyPath("RenderTransform.ScaleX"));
            Storyboard.SetTarget(growAnimation, image);
            storyboardh.Begin();

            Storyboard.SetTargetProperty(growAnimation, new PropertyPath("RenderTransform.ScaleY"));
            Storyboard.SetTarget(growAnimation, image);
            storyboardv.Begin();
        }

        private void slider_ValueChanged(object sender, System.Windows.RoutedPropertyChangedEventArgs<double> e)
        {
            double zoomChange = (SlideLevel - slider.Value) * -1;
            SlideLevel = SlideLevel + zoomChange;

            ZoomImage(zoomChange);
        }
    }
}

I found this other stack question to be quite helpful

Here is the current setup of XAML that I have as well.

    <Border MaxWidth="500"
        MaxHeight="500"
        Height="500"
        Width="500"
        Name="border">
    <Image
        Name="image"
        Source="picture1.png"
        Opacity="1"
        VerticalAlignment="Center"
        HorizontalAlignment="Center"
        Stretch="Fill"
        RenderTransformOrigin="0.5,0.5"
        RenderOptions.BitmapScalingMode="HighQuality"
        ClipToBounds="True">
    </Image>
    </Border>
    <Slider
        HorizontalAlignment="Left"
        Margin="44,70,0,148"
        Name="slider"
        Width="24"
        Value="1.0"
        Minimum="0"
        Maximum="1.0"
        LargeChange="0.1"
        Orientation="Vertical"
        FlowDirection="LeftToRight"
        TickFrequency="0.1"
        IsSnapToTickEnabled="False"
        ValueChanged="slider_ValueChanged" />
Community
  • 1
  • 1
Scott Boettger
  • 3,657
  • 2
  • 33
  • 44
1

Have you tried using a ViewBox? You can bind the final width to any value you need, here's a quick sample:

<Window.Resources>
    <Storyboard x:Key="ZoomIn">
        <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(FrameworkElement.Width)" Storyboard.TargetName="ImageContainer">
            <EasingDoubleKeyFrame KeyTime="0:0:0.5" Value="400"/>
        </DoubleAnimationUsingKeyFrames>
    </Storyboard>
</Window.Resources>

<Grid x:Name="LayoutRoot">
    <Viewbox x:Name="ImageContainer" Width="200">
        <Image Source="http://images.wikia.com/lossimpson/es/images/a/a7/Homer_Simpson2.png"/>
    </Viewbox>
</Grid>