实现WP7下ListBox分页加载接口

  APP开发,列表的分页加载是再常见不过的需求,我以前对每个需要分页加载的列表控件都写了一套分页加载逻辑,后来看官方的Demo,才发现其实这些相似的代码是可以封装起来的。基于WinRT开发APP的人应该知道,在WinRT下有ISupportIncrementalLoading这么一个接口,这个接口一个很重要的作用就是可以实现列表控件的分页加载。比如ListView,当ListView的ItemSource绑定的数据源实现了ISupportIncrementalLoading接口,那么当滑动到ListView底部的时候,会自动调用ISupportIncrementalLoading的方法实现自动加载。

  可是在基于Silverlight的WP上是没有ISupportIncrementalLoading这个接口的,那下面就在Wp7上来实现一个简易版的列表分页加载接口。

  首先我们定义这个接口,这个接口只有一个方法:LoadMoreAsync,这个方法的作用就是根据参数加载数据,你可以把参数理解成PageSize。

    public interface ISupportIncrementalLoading
    {
        Task<LoadMoreItemsResult> LoadMoreAsync(uint count);
    }

  当我们加载一页数据,会有一些通用的逻辑,比如说判断是否还有下一页;比如说,在加载前后我们可能还要进行一些操作,这些都可以封装起来,所以我们定义一个抽象类来实现这个逻辑,此外,当我们加载数据往往是多条,并且要实现集合绑定,以便在界面显示新加载数据,这里为了简便我们直接让抽象类继承ObservableCollection<T>。抽象类定义如下:

 public abstract class IncrementalLoadingDataSource<T> : ObservableCollection<T>, ISupportIncrementalLoading
    {
        public async Task<LoadMoreItemsResult> LoadMoreAsync(uint count)
        {
            if (CanLoadMore())
            {
                ICollection<T> list = await LoadMore(count);
                foreach (var item in list)
                {
                    this.Add(item);
                }
                return new LoadMoreItemsResult() { LoadedCount = list.Count };
            }
            else
            {
                return new LoadMoreItemsResult() { LoadedCount = 0 };;
            }
        }

        protected abstract Task<ICollection<T>> LoadMore(uint count);

        protected abstract bool CanLoadMore();
    }

  抽象类的实现逻辑比较简单,主要是判断是否还有下一页,如果有就请求下一页数据。这里有两个抽象方法我们没有实现,因为真正加载数据以及判断是否还有下一页可能都是跟业务相关,需要各自具体实现的,因此这里没有具体实现。这里给出一个实现样例,比如我们要实现StudentInfo的分页加载,可以如下定义:

public class StudentInfo
    {
        public string Name { get; set; }
    }

    public class Students : IncrementalLoadingDataSource<StudentInfo>
    {
        protected async override Task<ICollection<StudentInfo>> LoadMore(uint count)
        {
            return await Task.Factory.StartNew<ICollection<StudentInfo>>(() => 
            {
                List<StudentInfo> list = new List<StudentInfo>();
                for (int i = 0; i < count; i++)
                {
                    list.Add(new StudentInfo() { Name = i.ToString() });
                }

                return list;
            });
        }

        protected override bool CanLoadMore()
        {
            return true;
        }
    }

   现在接口都已经定义好了,我们的目的是让所有继承自IncrementalLoadingDataSource的实体数据都可以分页加载。

  我们该如何把接口ISupportIncrementalLoading与我们的列表控件关联起来?这里我们借助附加属性来实现,我们定义一个类叫IncrementalLoadingHelper,类中定义一个附加属性叫IncrementalLoading,只有当列表控件的IncrementalLoading为true时,并且列表控件的ItemsSource的数据源实现ISupportIncrementalLoading就可以分页加载。IncrementalLoadingHelper定义如下,其主要逻辑是在设置IncrementalLoading时,获取到列表控件,进而获取到列表控件的ScrollBar,并绑定ScrollBar的ValueChanged事件,在ValueChanged事件中,判断是否到底部,如果到底部,则调用列表控件的ItemsSource的LoadMoreAsync方法,前面介绍过,ItemsSource必须实现ISupportIncrementalLoading接口。

public class IncrementalLoadingHelper
    {
        public const uint PAGE_SIZE = 25;

        public static DependencyProperty IncrementalLoadingProperty =
            DependencyProperty.RegisterAttached("IncrementalLoading", typeof(Boolean), typeof(IncrementalLoadingHelper), new PropertyMetadata(false, IncrementalLoadingPropertyChangedCallback));
        private static ItemsControl _itemsControl;

        public static void SetIncrementalLoading(DependencyObject obj, bool val)
        {
            obj.SetValue(IncrementalLoadingProperty, val);
        }

        public static bool GetIncrementalLoading(DependencyObject obj)
        {
            return (bool)obj.GetValue(IncrementalLoadingProperty);
        }

        private static void IncrementalLoadingPropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ItemsControl control = d as ItemsControl;
            ScrollBar scrollBar = GetChild<ScrollBar>(d);
            if (control != null && scrollBar != null && control.Items.Count > 0)
            {
                scrollBar.Tag = control;
                _itemsControl = control;
                var isupport = control.ItemsSource as  ISupportIncrementalLoading;
                if (isupport != null)
                {
                    scrollBar.ValueChanged += scrollBar_ValueChanged;
                }
            }
        }

        static async void scrollBar_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
        {
            ScrollBar scrollBar = sender as ScrollBar;
            double max = (double)scrollBar.GetValue(ScrollBar.MaximumProperty);
            if (e.NewValue + 1 >= max)
            {
                var control = scrollBar.Tag as ItemsControl;
                if (control != null)
                {
                    var result = await ((ISupportIncrementalLoading)control.ItemsSource).LoadMoreAsync(PAGE_SIZE);
                }
            }
        }

        public static T GetChild<T>(DependencyObject element) where T : DependencyObject
        {
            T result = null;
            Queue<DependencyObject> quene = new Queue<DependencyObject>();
            quene.Enqueue(element);
            while (quene.Count > 0)
            {
                DependencyObject ele = quene.Dequeue();
                int count = VisualTreeHelper.GetChildrenCount(ele);
                for (int i = 0; i < count; i++)
                {
                    DependencyObject child = VisualTreeHelper.GetChild(ele, i);
                    result = child as T;
                    if (result != null) return result;
                    quene.Enqueue(child);
                }
            }
            return result;
        }
   }

   现在,假设我们页面上有一个需要实现学生分页加载的列表控件ListBox名字叫lstStudent,那么我们需要做以下两步就可以了:

  1)在页面或者列表控件Loaded事件中设置附加属性IncrementaLoading的值为ture;

  2)new一个新的Student实例赋值给lstStudent的ItemsSource。

 private void LayoutRoot_Loaded(object sender, RoutedEventArgs e)
        {
          lstStudent.SetValue(IncrementalLoadingHelper.IncrementalLoadingProperty, true);
        }

     public async void LoadData()
        {
            var data = new Students();
            await data.LoadMoreAsync(IncrementalLoadingHelper.PAGE_SIZE);
            lstStudent.ItemsSource = data;
        }

   下拉一下,是不是可以分页加载了!

原文地址:https://www.cnblogs.com/zhengldg/p/4257151.html