Storyboard Animation for the ScrollViewer: AnimationHelperControl

13 09 2008

The Scrollviewer is a great panel and very easy to use. But it has a drawback. It uses a method to set the scrollbars and content position. This means you cannot use a storyboard animation to animate this.

I had 2 projects that required this functionality, and really needed a better solutions then using a DispatcherTimer to create the animation manually. And after a few good nights of sleep (I always have the best ideas after a good nights rest) I came up with what I think is a nice solution.

The idea is that you need a DependencyProperty to animate a Scrollviewer. But since the ScrollViewer is a Sealed control you can’t inherit from it, I needed to wrap a new control around it to make it reusable.

So I took a different approach, I created a AnimationHelperControl, which does not have any visuals but only has a Dependency property and an event that is fired when this property has been changed. In this way you can use it to control anything you want.

Below the source code for the control:

public class AnimationHelperControl : Control

{

    public AnimationHelperControl()

    {

        Visibility = Visibility.Collapsed;

    }

 

    public double DoubleValue

 

    {

        get { return (double)GetValue(DoubleValueProperty); }

        set

        {

            SetValue(DoubleValueProperty, value);

            DoubleValueChanged(value);

        }

    }

 

    public static readonly DependencyProperty DoubleValueProperty =

        DependencyProperty.Register("DoubleValue", typeof(double), typeof(AnimationHelperControl), new PropertyMetadata((sender, e) =>

            {

                if (e.OldValue != e.NewValue)

                {

                    var ah = (AnimationHelperControl)sender;

                    ah.DoubleValue = (double)e.NewValue;

                }

            }));

 

    public event EventHandler<DoubleEventArgs> DoubleValueChange;

    private void DoubleValueChanged(double newValue)

    {

        if (DoubleValueChange != null)

            DoubleValueChange(this, new DoubleEventArgs() { Value = newValue });

    }

}

 

public class DoubleEventArgs : EventArgs

{

 

    private double _Value;

    public double Value

    {

        get { return _Value; }

        set { _Value = value; }

    }

 

}

 

Then you add the control, the scrollviewer and 2 buttons to the page.xaml:

<Grid x:Name="LayoutRoot" Background="White">

    <Grid.RowDefinitions>

        <RowDefinition Height="0.853*"/>

        <RowDefinition Height="0.147*"/>

    </Grid.RowDefinitions>

    <local:AnimationHelperControl x:Name="xScrollViewerHorizontalOffset" Grid.RowSpan="2"/>

    <Grid Grid.RowSpan="1" Margin="0,0,0,0">

        <ScrollViewer x:Name="xScrollViewer" VerticalScrollBarVisibility="Hidden" HorizontalScrollBarVisibility="Hidden">

            <ScrollViewer.Content>

                <StackPanel Orientation="Horizontal" HorizontalAlignment="Left">

                    <Rectangle Fill="Red" Width="300" Height="200" Margin="20,0,20,0"/>

                    <Rectangle Fill="Blue" Width="300" Height="200" Margin="0,0,20,0"/>

                    <Rectangle Fill="Green" Width="300" Height="200" Margin="0,0,20,0"/>

                    <Rectangle Fill="Purple" Width="300" Height="200" Margin="0,0,20,0"/>

                    <Rectangle Fill="Black" Width="300" Height="200" Margin="0,0,20,0"/>

                    <Rectangle Fill="Yellow" Width="300" Height="200" Margin="0,0,20,0"/>

                    <Rectangle Fill="Cyan" Width="300" Height="200" Margin="0,0,20,0"/>

                </StackPanel>

            </ScrollViewer.Content>

        </ScrollViewer>

    </Grid>

    <Button HorizontalAlignment="Left" Margin="8,8,0,8" VerticalAlignment="Stretch" Width="65" Content="Left" Grid.Row="1" x:Name="xButtonLeft"/>

    <Button HorizontalAlignment="Right" Margin="0,8,8,8" VerticalAlignment="Stretch" Width="66" Content="Right" Grid.Row="1" x:Name="xButtonRight"/>

</Grid>

 

Remember to the "local" namespace to the xaml.

Then we add the event handler to the page.xaml.cs:

xScrollViewerHorizontalOffset.DoubleValueChange += (sender, e) =>

{

    this.xScrollViewer.ScrollToHorizontalOffset(e.Value);

};

Now you could create storyboard animation on the DoubleValue property of the xScrollViewerHorizontalOffset control, but to keep it short and simple I’ll use the AnimateTo extension method of one of my previous posts, which accomplishes the same, only it does it with code. Let’s use the 2 buttons to animate scrolling left and right.

xButtonRight.Click += (sender, e) =>

{

    xScrollViewerHorizontalOffset.AnimateDoubleTo(200, "(StoryboardAnimationHelper.DoubleValue)", xScrollViewer.HorizontalOffset + 320);

};

xButtonLeft.Click += (sender, e) =>

{

    xScrollViewerHorizontalOffset.AnimateDoubleTo(200, "(StoryboardAnimationHelper.DoubleValue)", xScrollViewer.HorizontalOffset - 320);

};

 

That should do the trick I’ll try to upload a Demo Project later this weekend.

Stay in the light!

Robertjan Tuit


Actions

Informations

6 responses to “Storyboard Animation for the ScrollViewer: AnimationHelperControl”

6 11 2008
Anders (2.46 pm) :

Very smart idea Roberjan!

I’m trying to use the same solution in WPF instead of Silverlight but fail. It’s something wrong with the mysterious property path string. I get an InvalidOperationException from the Storyboard.Begin() call within AnimateToDouble(…) with the exception message:
“Cannot resolve all property references in the property path ‘(StoryboardAnimationHelper.DoubleValue)’. Verify that applicable objects support the properties.”

I cannot say I’m understanding how the property path string is constructed and I’ve tried a number of alternatives that I thought would be correct but with the same result. E.g., my best guess was that the property path string should have been “(AnimationHelperControl.DoubleValue)”…but no…

Perhaps I’m missing something fundamental. Did you upload you Demo project somewhere that I might get some clues from?

Thanks,
Anders

11 11 2008
robertjantuit (1.20 am) :

Hi Anders,

I’m not sure what is causing the error in your application, not that familiar with WPF. I’ll try to upload a Demo Project kater today so you can compare it yourself.

Cheers,
Robertjan

13 11 2008
Anders (10.17 am) :

Thanks Robertjan,
It feels like the same idea should be possible to apply with WPF as it’s basically the same thing as Silverlight….but I might be wrong… I look forward to your demo project.

I really appreciate your help,
Anders

12 01 2009
Rik Robinson's Blog : Silverlight 2 Scroller (10.06 pm) :

[…] what I thought was a really cool solution on Rob’s Usability Development blog for creating an AnimationHelperControl to give you something to animate.  His post also made use of his excellent AnimateTo extension […]

23 01 2009
Záboj Jan (9.30 am) :

hi…please i need help…i have animation in silverlight with one storyboadr…and i need after push button set a new value of time and resume storyboard…can you halp me please:-)…thank you..;-)

23 01 2009
Záboj Jan (4.21 pm) :

i have got it…thanks…;-)

Leave a comment

You can use these tags : <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <code> <em> <i> <strike> <strong>