• 实现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;
            }

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

  • 相关阅读:
    Android开发学习总结(一)——搭建最新版本的Android开发环境
    EntityFramework 6
    EntityFramework优缺点
    十分钟轻松让你认识Entity Framework 7
    SqlServer中的merge操作(转载)
    python打印即时输出的方法
    我的人工智能机器人的游戏
    网络编程的一些知识
    hdu4722 Good Numbers
    hdu4727 The Number Off of FFF
  • 原文地址:https://www.cnblogs.com/zhengldg/p/4257151.html
Copyright © 2020-2023  润新知