posts - 615, comments - 10491, trackbacks - 594, articles - 0
  博客园 :: 首页 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理

公告

重新想象 Windows 8 Store Apps (54) - 绑定: 增量方式加载数据

Posted on 2013-08-26 08:17 webabcd 阅读(...) 评论(...) 编辑 收藏

[源码下载]


重新想象 Windows 8 Store Apps (54) - 绑定: 增量方式加载数据



作者:webabcd


介绍
重新想象 Windows 8 Store Apps 之 绑定

  • 通过实现 ISupportIncrementalLoading 接口,为 ListViewBase 的增量加载提供数据



示例
实现 ISupportIncrementalLoading 接口,以便为 ListViewBase 的增量加载提供数据
Binding/MyIncrementalLoading.cs

/*
 * 演示如何实现 ISupportIncrementalLoading 接口,以便为 ListViewBase 的增量加载提供数据
 * 
 * ISupportIncrementalLoading - 用于支持增量加载
 *     HasMoreItems - 是否还有更多的数据
 *     IAsyncOperation<LoadMoreItemsResult> LoadMoreItemsAsync(uint count) - 异步加载指定数量的数据(增量加载)
 *    
 * LoadMoreItemsResult - 增量加载的结果
 *     Count - 实际已加载的数据量
 */

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Runtime.InteropServices.WindowsRuntime;
using System.Threading.Tasks;
using Windows.Foundation;
using Windows.UI.Core;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Data;

namespace XamlDemo.Binding
{
    public class MyIncrementalLoading<T> : ObservableCollection<T>, ISupportIncrementalLoading
    {
        // 是否正在异步加载中
        private bool _isBusy = false;

        // 提供数据的 Func
        // 第一个参数:增量加载的起始索引;第二个参数:需要获取的数据量;第三个参数:获取到的数据集合
        private Func<int, int, List<T>> _funcGetData;
        // 最大可显示的数据量
        private uint _totalCount = 0;

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="totalCount">最大可显示的数据量</param>
        /// <param name="getDataFunc">提供数据的 Func</param>
        public MyIncrementalLoading(uint totalCount, Func<int, int, List<T>> getDataFunc)
        {
            _funcGetData = getDataFunc;
            _totalCount = totalCount;
        }

        /// <summary>
        /// 是否还有更多的数据
        /// </summary>
        public bool HasMoreItems
        {
            get { return this.Count < _totalCount; }
        }

        /// <summary>
        /// 异步加载数据(增量加载)
        /// </summary>
        /// <param name="count">需要加载的数据量</param>
        /// <returns></returns>
        public IAsyncOperation<LoadMoreItemsResult> LoadMoreItemsAsync(uint count)
        {
            if (_isBusy)
            {
                throw new InvalidOperationException("忙着呢,先不搭理你");
            }
            _isBusy = true;

            var dispatcher = Window.Current.Dispatcher;

            return AsyncInfo.Run(
                (token) =>
                    Task.Run<LoadMoreItemsResult>(
                       async () =>
                       {
                           try
                           {
                               // 模拟长时任务
                               await Task.Delay(1000);

                               // 增量加载的起始索引
                               var startIndex = this.Count;

                               await dispatcher.RunAsync(
                                    CoreDispatcherPriority.Normal,
                                    () =>
                                    {
                                        // 通过 Func 获取增量数据
                                        var items = _funcGetData(startIndex, (int)count);
                                        foreach (var item in items)
                                        {
                                            this.Add(item);
                                        }
                                    });

                               // Count - 实际已加载的数据量
                               return new LoadMoreItemsResult { Count = (uint)this.Count };
                           }
                           finally
                           {
                               _isBusy = false;
                           }
                       },
                       token));
        }
    }
}


演示如何实现 ListViewBase 的增量加载
Binding/IncrementalLoading.xaml

<Page
    x:Class="XamlDemo.Binding.IncrementalLoading"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:XamlDemo.Binding"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">

    <Grid Background="Transparent">
        <Grid Margin="120 0 0 10">

            <TextBlock Name="lblMsg" FontSize="14.667" />

            <ListView x:Name="listView" Width="300" Height="300" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="0 30 0 0">
                <ListView.ItemTemplate>
                    <DataTemplate>
                        <Border Background="Blue" Width="200" CornerRadius="3" HorizontalAlignment="Left">
                            <TextBlock Text="{Binding Name}" FontSize="14.667" />
                        </Border>
                    </DataTemplate>
                </ListView.ItemTemplate>
            </ListView>

            <TextBlock Name="lblLog" FontSize="14.667" Margin="0 350 0 0" />
        </Grid>
    </Grid>
</Page>

Binding/IncrementalLoading.xaml.cs

/*
 * 演示如何实现 ListViewBase 的增量加载
 * 数据源需要实现 ISupportIncrementalLoading 接口,详见:MyIncrementalLoading.cs
 * 
 * 
 * ListViewBase - ListView 和 GridView 均继承自 ListViewBase
 *     IncrementalLoadingTrigger - 增量加载的触发方式(IncrementalLoadingTrigger 枚举)
 *         Edge - 允许触发增量加载,默认值
 *         None - 禁止触发增量加载
 *     DataFetchSize - 预提数据的大小,默认值 3.0
 *         本例将此值设置为 4.0 ,其效果为(注:本例中的 ListView 每页可显示的数据量为 6 条或 7 条,以下计算需基于此)
 *         1、先获取 1 条数据,为的是尽量快地显示数据
 *         2、再获取 4.0 * 1 条数据
 *         3、再获取 4.0 * (6 或 7,如果 ListView 当前显示了 6 条数据则为 6,如果 ListView 当前显示了 7 条数据则为 7) 条数据
 *         4、以后每次到达阈值后,均增量加载 4.0 * (6 或 7,如果 ListView 当前显示了 6 条数据则为 6,如果 ListView 当前显示了 7 条数据则为 7) 条数据
 *     IncrementalLoadingThreshold - 阈值,默认值 0.0
 *         本例将此值设置为 2.0 ,其效果为(注:本例中的 ListView 每页可显示的数据量为 6 条或 7 条)
 *         1、滚动中,如果已准备好的数据少于 2.0 * (6 或 7,如果 ListView 当前显示了 6 条数据则为 6,如果 ListView 当前显示了 7 条数据则为 7) 条数据,则开始增量加载  
 */

using Windows.UI.Xaml.Controls;
using XamlDemo.Model;
using System.Linq;
using System.Collections.Specialized;
using System;

namespace XamlDemo.Binding
{
    public sealed partial class IncrementalLoading : Page
    {
        // 实现了增量加载的数据源
        private MyIncrementalLoading<Employee> _employees;

        public IncrementalLoading()
        {
            this.InitializeComponent();

            this.Loaded += IncrementalLoading_Loaded;
        }

        void IncrementalLoading_Loaded(object sender, Windows.UI.Xaml.RoutedEventArgs e)
        {
            listView.IncrementalLoadingTrigger = IncrementalLoadingTrigger.Edge;
            listView.DataFetchSize = 4.0;
            listView.IncrementalLoadingThreshold = 2.0;

            _employees = new MyIncrementalLoading<Employee>(1000, (startIndex, count) =>
            {
                lblLog.Text += string.Format("从索引 {0} 处开始获取 {1} 条数据", startIndex, count);
                lblLog.Text += Environment.NewLine;

                return TestData.GetEmployees().Skip(startIndex).Take(count).ToList();
            });

            _employees.CollectionChanged += _employees_CollectionChanged;

            listView.ItemsSource = _employees;
        }

        void _employees_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            lblMsg.Text = "已获取的数据量:" + _employees.Count.ToString();
        }
    }
}



OK
[源码下载]