2017-01-10 1 views
1

Ich versuche, eine Anforderung zu erstellen, die jeweils 10 Elemente vom Server für jede Anforderung lädt. Wenn beispielsweise ein Benutzer auf eine Schaltfläche klickt und sie zur nächsten Seite weiterleitet, möchte ich, dass die ersten 10 Elemente zuerst angezeigt werden, während die Anforderungen für die anderen Elemente im Hintergrund ausgeführt werden. Wie soll ich das machen? Ich habe eine Idee, wie es funktionieren könnte, auf der Server-Seite, indem Sie die maximale Anzahl zurückgeben und von einer Startposition bei jeder Anfrage, aber ist das der richtige Weg, es zu betrachten?Laden von Daten in Schritten von zehn Elementen pro Ergebnis Xamarin-Formulare

Antwort

3

Ja, das klingt nach einem guten Weg, damit umzugehen. Dies wird oft als "Paginierung" von Daten bezeichnet.

Lassen Sie von Ihrer API einen Offset behandeln, für den die "Seite" der Daten, die Sie erhalten möchten, und die Anzahl der maximal für diese Seite zurückzugebenden Elemente (Seitengröße) zählt. Hier ist ein Beispiel, wie Sie dies für Formulare implementieren können.

Ein Vertrag für Ihr Ansichtsmodell umzusetzen:

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

    bool HasMoreItems { get; set; } 

    bool IsLoading { get; } 

    Task LoadMoreItemsAsync(); 
} 

eine Beispielimplementierung in einem Ansichtsmodell:

#region ISupportIncrementalLoading Implementation 

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

public bool HasMoreItems { get; set; } 

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

//... 

#endregion 

Beispiel 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); 
}); 

Um dies automatisch in einem Steuerelement wie einem ListView zu unterstützen, können Sie einen Renderer oder "Effekt" anpassen, um dies zu tun. Hier ist eine beschnittene Beispiel:

// 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(); 
     } 
    } 
} 

Diese Techniken aus this Plugin nutzt.