以每个结果Xamarin表单的十个项目的增量加载数据

时间:2017-01-10 20:18:45

标签: xamarin.forms

我正在尝试构建一个请求,每次从服务器为每个请求加载10个项目。例如,当用户单击按钮,将它们重定向到下一页时,我希望首先显示前10个项目,而在后台进行其他项目的请求。我该怎么做呢?我知道它是如何工作的,在服务器端通过设置返回的最大数量和每个请求的起始位置,但这是正确的查看方式吗?

1 个答案:

答案 0 :(得分:3)

是的,这听起来像是处理它的好方法。这通常被称为数据的“分页”。

让您的API处理您想要接收的数据“页面”的偏移量以及该页面返回的最大项目数(pagesize)。以下是如何为Forms实现此功能的示例。

ViewModel实施的合同:

public interface ISupportIncrementalLoading
{
    int PageSize { get; set; }

    bool HasMoreItems { get; set; }

    bool IsLoading { get; }

    Task LoadMoreItemsAsync();
}

ViewModel中的示例实现:

#region ISupportIncrementalLoading Implementation

public int PageSize { get; set; } = 10;

public bool HasMoreItems { get; set; }

public async Task LoadMoreItemsAsync()
{
    await LoadMoreItemsCommand.ExecuteAsyncTask();
}

//...

#endregion

示例LoadMoreItemsCommand:

LoadMoreItemsCommand = new Command(async () =>
{
    int fetchOffset = Requests.Count;
    int fetchMax = PageSize;

    // "Pagination" of your API request starting at the offset
    // and getting a maximum of the `fetchMax` or "page size"
    Results = await GetRequestsAsync(fetchOffset, fetchMax);
});

要在像ListView这样的控件中自动支持此功能,您可以自定义渲染器或“效果”来执行此操作。这是一个修剪过的例子:

// Custom ListViewRenderer, iOS example
public class IncrementalListViewRenderer : ListViewRenderer
{
    public IncrementalListViewRenderer()
    {
    }

    protected override void OnElementChanged(ElementChangedEventArgs<ListView> e)
    {
        base.OnElementChanged(e);

        if (Control != null)
        {
            // Need to customize the source but not lose existing functionality so 
            // we need a copy of it to use
            UITableViewSource defaultSource = Control.Source;            
            Control.Source = new IncrementalDataSource(Element as IncrementalListView, defaultSource);            
        }
    }

    class IncrementalDataSource : UITableViewSource
    {
        readonly UITableViewSource existingSource;
        readonly IncrementalListView listView;
        readonly ISupportIncrementalLoading incrementalLoading;

        int lastPosition;
        int preloadMargin = 5;

        public IncrementalDataSource(IncrementalListView listView, UITableViewSource existingSource)
        {
            this.listView = listView;
            this.existingSource = existingSource;

            incrementalLoading = listView.BindingContext as ISupportIncrementalLoading;

            lastPosition = 0;

            LoadMoreItems();
        }

        public override UITableViewCell GetCell(UITableView tableView, NSIndexPath indexPath)
        {
            int position = indexPath.Row;
            var itemsSource = listView.ItemsSource as IList;

            if (itemsSource != null)
            {
                int preloadIndex = Math.Max(itemsSource.Count - preloadMargin, 0);

                if ((position > lastPosition || (position == itemsSource.Count - 1)) && (position >= preloadIndex))
                {
                    lastPosition = position;

                    if(!incrementalLoading.IsLoading && incrementalLoading.HasMoreItems)
                        LoadMoreItems();
                }
            }

            var cell = existingSource.GetCell(tableView, indexPath);
            cell.SelectionStyle = UITableViewCellSelectionStyle.None;

            return cell;
        }

        public override void RowSelected(UITableView tableView, NSIndexPath indexPath)
        {
            existingSource.RowSelected(tableView, indexPath);
        }

        public override nint RowsInSection(UITableView tableview, nint section)
        {
            return existingSource.RowsInSection(tableview, section);
        }

        void LoadMoreItems()
        {
            // Note the use of Nito.AsyncEx lib
            INotifyTaskCompletion taskCompletion = NotifyTaskCompletion.Create(LoadMoreItemsAsync());
        }

        public async Task LoadMoreItemsAsync()
        {
            await incrementalLoading.LoadMoreItemsAsync();
        }
    }
}

这利用了this插件中的技术。