ScrollViewer.EnsureVisible for Windows Phone

Sat, July 30, 2011, 08:06 PM under MobileAndEmbedded

In my Translator By Moth app, on both the current and saved pivot pages the need arose to programmatically scroll to the bottom. In the former, case it is when a translation takes place (if the text is too long, I want to scroll to the bottom of the translation so the user can focus on that, and not their input text for translation). In the latter case it was when a new translation is saved (it is added to the bottom of the list, so scrolling is required to make it visible). On both pages a ScrollViewer is used.

In my exploration of the APIs through intellisense and msdn I could not find a method that auto scrolled to the bottom. So I hacked together a solution where I added a blank textblock to the bottom of each page (within the ScrollViewer, but above the translated textblock and the saved list) and tried to make it scroll it into view from code. After searching the web I found a little algorithm that did most of what I wanted (sorry, I do not have the reference handy, but thank you whoever it was) that after minor tweaking I turned into an extension method for the ScrollViewer that is very easy to use:

	this.Scroller.EnsureVisible(this.BlankText);

The method itself I share with you here:

    public static void EnsureVisible(this System.Windows.Controls.ScrollViewer scroller, 
                                          System.Windows.UIElement uiElem)
    {
      System.Diagnostics.Debug.Assert(scroller != null);
      System.Diagnostics.Debug.Assert(uiElem != null);

      scroller.UpdateLayout();

      double maxScrollPos = scroller.ExtentHeight - scroller.ViewportHeight;
      double scrollPos = 
              scroller.VerticalOffset - 
              scroller.TransformToVisual(uiElem).Transform(new System.Windows.Point(0, 0)).Y;

      if (scrollPos > maxScrollPos) scrollPos = maxScrollPos;
      else if (scrollPos < 0) scrollPos = 0;

      scroller.ScrollToVerticalOffset(scrollPos);
    }

I am sure there are better ways, but this "worked for me" :-)