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