title: Animate (smoothly) ScrollViewer programmatically
body: <p>Is there a way to smoothly animate a <code>ScrollViewer</code>s vertical offset in Windows Phone 8.1 Runtime?</p>
  
  <p>I have tried using the <code>ScrollViewer.ChangeView()</code> method and the change of vertical offset is not animated no matter if I set the <code>disableAnimation</code> parameter to true or false.</p>
  
  <p>For example: <code>myScrollViewer.ChangeView(null, myScrollViewer.VerticalOffset + p, null, false);</code>
  The offset is changed without animation.</p>
  
  <p>I also tried using a vertical offset mediator:</p>
  
  <pre><code>/// &lt;summary&gt;
  /// Mediator that forwards Offset property changes on to a ScrollViewer
  /// instance to enable the animation of Horizontal/VerticalOffset.
  /// &lt;/summary&gt;
  public sealed class ScrollViewerOffsetMediator : FrameworkElement
  {
      /// &lt;summary&gt;
      /// ScrollViewer instance to forward Offset changes on to.
      /// &lt;/summary&gt;
      public ScrollViewer ScrollViewer
      {
          get { return (ScrollViewer)GetValue(ScrollViewerProperty); }
          set { SetValue(ScrollViewerProperty, value); }
      }
      public static readonly DependencyProperty ScrollViewerProperty =
              DependencyProperty.Register("ScrollViewer",
              typeof(ScrollViewer),
              typeof(ScrollViewerOffsetMediator),
              new PropertyMetadata(null, OnScrollViewerChanged));
      private static void OnScrollViewerChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
      {
          var mediator = (ScrollViewerOffsetMediator)o;
          var scrollViewer = (ScrollViewer)(e.NewValue);
          if (null != scrollViewer)
          {
              scrollViewer.ScrollToVerticalOffset(mediator.VerticalOffset);
          }
      }
  
      /// &lt;summary&gt;
      /// VerticalOffset property to forward to the ScrollViewer.
      /// &lt;/summary&gt;
      public double VerticalOffset
      {
          get { return (double)GetValue(VerticalOffsetProperty); }
          set { SetValue(VerticalOffsetProperty, value); }
      }
      public static readonly DependencyProperty VerticalOffsetProperty =
              DependencyProperty.Register("VerticalOffset",
              typeof(double),
              typeof(ScrollViewerOffsetMediator),
              new PropertyMetadata(0.0, OnVerticalOffsetChanged));
      public static void OnVerticalOffsetChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
      {
          var mediator = (ScrollViewerOffsetMediator)o;
          if (null != mediator.ScrollViewer)
          {
              mediator.ScrollViewer.ScrollToVerticalOffset((double)(e.NewValue));
          }
      }
  
      /// &lt;summary&gt;
      /// Multiplier for ScrollableHeight property to forward to the ScrollViewer.
      /// &lt;/summary&gt;
      /// &lt;remarks&gt;
      /// 0.0 means "scrolled to top"; 1.0 means "scrolled to bottom".
      /// &lt;/remarks&gt;
      public double ScrollableHeightMultiplier
      {
          get { return (double)GetValue(ScrollableHeightMultiplierProperty); }
          set { SetValue(ScrollableHeightMultiplierProperty, value); }
      }
      public static readonly DependencyProperty ScrollableHeightMultiplierProperty =
              DependencyProperty.Register("ScrollableHeightMultiplier",
              typeof(double),
              typeof(ScrollViewerOffsetMediator),
              new PropertyMetadata(0.0, OnScrollableHeightMultiplierChanged));
      public static void OnScrollableHeightMultiplierChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
      {
          var mediator = (ScrollViewerOffsetMediator)o;
          var scrollViewer = mediator.ScrollViewer;
          if (null != scrollViewer)
          {
              scrollViewer.ScrollToVerticalOffset((double)(e.NewValue) * scrollViewer.ScrollableHeight);
          }
      }
  }
  </code></pre>
  
  <p>and I can animate the <code>VerticalOffset</code> property with <code>DoubleAnimation</code>:</p>
  
  <pre><code>Storyboard sb = new Storyboard();
  DoubleAnimation da = new DoubleAnimation();
  da.EnableDependentAnimation = true;
  da.From = Mediator.ScrollViewer.VerticalOffset;
  da.To = da.From + p;
  da.Duration = new Duration(TimeSpan.FromMilliseconds(300));
  da.EasingFunction = new ExponentialEase() { EasingMode = EasingMode.EaseOut };
  Storyboard.SetTarget(da, Mediator);
  Storyboard.SetTargetProperty(da, "(Mediator.VerticalOffset)");
  sb.Children.Add(da);
  
  sb.Begin();
  </code></pre>
  
  <p>Mediator is declared in XAML.
  But this animation is not smooth on my device (Lumia 930).</p>