Friday, January 21, 2011

AutoLoading more content when you scroll to the bottom of a ListBox in WP7 (Windows Phone 7)

I've just implemented this for Overflow7.

The approach I took was similar to http://blog.slimcode.com/2010/09/11/detect-when-a-listbox-scrolls-to-its-end-wp7/

However, instead of using a Style I did the hook up in code.

Basically derived my parent UserControl from:

     public class BaseExtendedListUserControl : UserControl
{
   
DependencyProperty ListVerticalOffsetProperty = DependencyProperty.Register(
     
"ListVerticalOffset",
     
typeof(double),
     
typeof(BaseExtendedListUserControl),
     
new PropertyMetadata(new PropertyChangedCallback(OnListVerticalOffsetChanged)));

   
private ScrollViewer _listScrollViewer;

   
protected void EnsureBoundToScrollViewer()
   
{
       
if (_listScrollViewer != null)
           
return;

       
var elements = VisualTreeHelper.FindElementsInHostCoordinates(new Rect(0,0,this.Width, this.Height), this);

        _listScrollViewer
= elements.Where(x => x is ScrollViewer).FirstOrDefault() as ScrollViewer;

       
if (_listScrollViewer == null)
           
return;

       
Binding binding = new Binding();
        binding
.Source = _listScrollViewer;
        binding
.Path = new PropertyPath("VerticalOffset");
        binding
.Mode = BindingMode.OneWay;
       
this.SetBinding(ListVerticalOffsetProperty, binding);
   
}

   
public double ListVerticalOffset
   
{
        get
{ return (double)this.GetValue(ListVerticalOffsetProperty); }
        set
{ this.SetValue(ListVerticalOffsetProperty, value); }
   
}

   
private static void OnListVerticalOffsetChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
   
{
       
BaseExtendedListUserControl control = obj as BaseExtendedListUserControl;
        control
.OnListVerticalOffsetChanged();
   
}

   
private void OnListVerticalOffsetChanged()
   
{
       
OnListVerticalOffsetChanged(_listScrollViewer);

   
}

   
protected virtual void OnListVerticalOffsetChanged(ScrollViewer s)
   
{
       
// do nothing
   
}
}

this then meant that in the user control itself I could just use:

         protected override void OnListVerticalOffsetChanged(ScrollViewer viewer)
   
{
       
// Trigger when at the end of the viewport
       
if (viewer.VerticalOffset >= viewer.ScrollableHeight)
       
{
                // actually do the load here!
        }
   
}

   
private void ListBox1_ManipulationCompleted(object sender, ManipulationCompletedEventArgs e)
   
{
       
EnsureBoundToScrollViewer();
   
}

The "hacky" thing here was that I had to use ListBox1_ManipulationCompleted and VisualTreeHelper to find my ScrollViewer - I'm sure there are better ways...

No comments:

Post a Comment