开发者

WP7 Auto Grow ListBox upon reaching the last item

I'm trying to achieve an effect where more items are appended to the list when the user scrolls down to the last item. I haven't found a way to determine if the user has scrolled to the end of the list. I don't see a event on ListBox that is fired when the user reaches the bottom of the list. Something that tells me when an item has been scrolled into view would be great, but as far as I can tell, there is nothing like that.

Is this even possible in WP7?

Edit: Ano开发者_JS百科ther way of saying this is, can we detect when a list has "bounced"?


Daniel Vaughan has posted an example of how to detect for this at http://danielvaughan.orpius.com/post/Scroll-Based-Data-Loading-in-Windows-Phone-7.aspx


It isn't super easy to get going since there are a lot of moving parts, but here is what you can do, assuming you want a short list that loads more from your data as you get scrolling down, similar to a lot of twitter apps, etc.

  • Write your own subclass of ObservableCollection that only offers up a few items (like 20), keeping the rest held back until requested
  • Hook up to the scroll viewer (inside the listbox or container) and its visual state changed events, you can get the NotScrolling and Scrolling changes; for an example see this code by ptorr
  • When scrolling stops, use viewer scroll extensions code to see where things are extended (at the bottom or not) or just the raw scroll viewer properties to see if it is extended to the bottom
  • If so, trigger your observable collection to release another set of items.

Sorry I don't have a complete sample ready to blog yet. Good luck!


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)
        {
            if (MoreClick != null)
            {
                MoreClick(this, new RoutedEventArgs());
            }
        }
    }

    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...


Have a look at this detect Listbox compression state from msdn blog


Use the DeferredLoadListBox.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜