2014-02-06 22 views
0

我使用ListView在Windows應用商店的XAML-C#中開發。使用ListView加載更多項目(Windows 8.1)

我想每次用戶到達列表的末尾時在ListView上加載更多的項目。

我剛剛看了這個討論Load more items on grid view scroll end和我剛剛看了這個例子http://code.msdn.microsoft.com/windowsapps/Data-Binding-7b1d67b5

我試圖執行像提到的例子: - 一些mycode的的

   uint nentries = 0; 

      // Follow method return a int: number of items (entries) between 0 and 20 
      nentries = await App.EntriesViewModel.LoadEntries(0); 
      if (nentries != 0) 
      { 
//entries is a GeneratorIncrementalLoadingClass<Entry> 
         App.EntriesViewModel.entries = new GeneratorIncrementalLoadingClass<Entry>(nentries, count => 
         { 
          //EntriesOc is an observable collection with INotifyPropertyChanged 
          return App.EntriesViewModel.EntriesOc.ElementAt(count); 
         }); 
    //entriesCVS is a CollectionViewSource defined into xaml code 
         entriesCVS.Source = App.EntriesViewModel.entries; 
        } 

      } 
      this.DataContext = null; 
      this.DataContext = App.EntriesViewModel; 

      //until here it's works 

      if (nentries == 20) 
      { 
       uint n = 0; 
       while (nentries % 20 == 0) 
       { 
        n = await App.EntriesViewModel.LoadEntries(nentries); 
        if (n == 0) break; // no more data to load 
        nentries += n; 
        App.EntriesViewModel.entries = new GeneratorIncrementalLoadingClass<Entry>(nentries, (count) => 
        { 
         return App.EntriesViewModel.EntriesOc.ElementAt(count); 
        }); 


        // without the follow line of code the CollectionViewSource doesn't update 
        // however the list scroll to the top (I want to remove this behaviour) 
        entriesCVS.Source = App.EntriesViewModel.entries; 
       } 
      } 
  • IncrementalLoadingBase.cs(同示例的文件)

    namespa CE MySolution {

    public abstract class IncrementalLoadingBase: IList, ISupportIncrementalLoading, INotifyCollectionChanged 
    
    { 
    
        public int Add(object value) 
        { 
         throw new NotImplementedException(); 
        } 
    
        public void Clear() 
        { 
         throw new NotImplementedException(); 
        } 
    
        public bool Contains(object value) 
        { 
         return _storage.Contains(value); 
        } 
    
        public int IndexOf(object value) 
        { 
         return _storage.IndexOf(value); 
        } 
    
        public void Insert(int index, object value) 
        { 
         throw new NotImplementedException(); 
        } 
    
        public bool IsFixedSize 
        { 
         get { return false; } 
        } 
    
        public bool IsReadOnly 
        { 
         get { return true; } 
        } 
    
        public void Remove(object value) 
        { 
         throw new NotImplementedException(); 
        } 
    
        public void RemoveAt(int index) 
        { 
         throw new NotImplementedException(); 
        } 
    
        public object this[int index] 
        { 
         get 
         { 
          return _storage[index]; 
         } 
         set 
         { 
          throw new NotImplementedException(); 
         } 
        } 
    
        public void CopyTo(Array array, int index) 
        { 
         ((IList)_storage).CopyTo(array, index); 
        } 
    
        public int Count 
        { 
         get { return _storage.Count; } 
        } 
    
        public bool IsSynchronized 
        { 
         get { return false; } 
        } 
    
        public object SyncRoot 
        { 
         get { throw new NotImplementedException(); } 
        } 
    
        public IEnumerator GetEnumerator() 
        { 
         return _storage.GetEnumerator(); 
        } 
    
    
        public bool HasMoreItems 
        { 
         get { return HasMoreItemsOverride(); } 
        } 
    
        public Windows.Foundation.IAsyncOperation<LoadMoreItemsResult> LoadMoreItemsAsync(uint count) 
        { 
         if (_busy) 
         { 
          throw new InvalidOperationException("Only one operation in flight at a time"); 
         } 
    
         _busy = true; 
    
         return AsyncInfo.Run((c) => LoadMoreItemsAsync(c, count)); 
        } 
    
    
        public event NotifyCollectionChangedEventHandler CollectionChanged; 
    
    
        async Task<LoadMoreItemsResult> LoadMoreItemsAsync(CancellationToken c, uint count) 
        { 
         try 
         { 
          var items = await LoadMoreItemsOverrideAsync(c, count); 
          var baseIndex = _storage.Count; 
    
          _storage.AddRange(items); 
    
          // Now notify of the new items 
          NotifyOfInsertedItems(baseIndex, items.Count); 
    
          return new LoadMoreItemsResult { Count = (uint)items.Count }; 
         } 
         finally 
         { 
          _busy = false; 
         } 
        } 
    
        void NotifyOfInsertedItems(int baseIndex, int count) 
        { 
         if (CollectionChanged == null) 
         { 
          return; 
         } 
    
         for (int i = 0; i < count; i++) 
         { 
          var args = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, _storage[i + baseIndex], i + baseIndex); 
          CollectionChanged(this, args); 
         } 
        } 
    
    
        protected abstract Task<IList<object>>LoadMoreItemsOverrideAsync(CancellationToken c, uint count); 
        protected abstract bool HasMoreItemsOverride(); 
    
    
        List<object> _storage = new List<object>(); 
        bool _busy = false; 
    
    } 
    

    }

  • GeneratorIncrementalLoadingClass.cs(實施例的相同的文件)

namespace MySolution{ 

公共類GeneratorIncrementalLoadingClass: IncrementalLoadingBase

{ 
 public GeneratorIncrementalLoadingClass(uint maxCount, Func<int, T> generator) 
     { 

      _generator = generator; 
      _maxCount = maxCount; 
     } 

     protected async override Task<IList<object>> LoadMoreItemsOverrideAsync(System.Threading.CancellationToken c, uint count) 
     { 
      uint toGenerate = System.Math.Min(count, _maxCount - _count); 

      // Wait for work 
      await Task.Delay(10); 

      // This code simply generates 
      var values = from j in Enumerable.Range((int)_count, (int)toGenerate) 
         select (object)_generator(j); 
      _count += toGenerate; 

      return values.ToArray(); 
     } 

     protected override bool HasMoreItemsOverride() 
     { 
      return _count < _maxCount; 
     } 


     Func<int, T> _generator; 
     uint _count = 0; 
     uint _maxCount; 

    } 
} 
+0

我們需要的一些東西:目前發生了什麼?應該發生什麼?項目是否加載?這些項目沒有改變? LoadMoreItemsOverrideAsync是否被調用? –

+0

調用LoadMoreItemsOverrideAsync。最後加載所有項目。我認爲while循環有問題。問題是每次執行while循環時,列表​​都會滾動到頂部:如果用戶嘗試在執行while循環時滾動到列表的末尾,則將滾動位置重置爲列表的頂部。 –

回答

1

什麼LoadMoreItemsOverrideAsync打算做的是填補現有的清單,更多的項目。你目前正在做的是每次重置列表。這就是爲什麼頁面每次都滾動到頂部。它正在加載一組全新的數據。

這是我的修復它的嘗試。

首先,如果你注意,在例子,他們解釋說MaxCount只是一個例子,而不是必要的。你真正想要的是讓列表知道它何時到達列表的末尾。這意味着它應該檢查nentries

你的新的IncrementalLoading實現應該看起來類似於這個(如果不是這樣的話)。

public class GeneratorIncrementalLoadingClass: IncrementalLoadingBase 
{ 
    private int _numLeft; 
    private Func<int, Task<int>> _loadMore; 

    public GeneratorIncrementalLoadingClass(Func<int, Task<int>> loadMore, Func<int, T> generator) 
    { 
     _loadMore = loadMore; 
     _generator = generator; 
    } 

    protected async override Task<IList<object>> LoadMoreItemsOverrideAsync(System.Threading.CancellationToken c, uint count) 
    { 
     // If count is greater than the max size that we know, load the difference first 
     List<object> returnList = new List<object>(); 
     if(count > 20) 
     { 
      var tempList = await LoadMoreItemsOverrideAsync(c, count); 
      returnList.AddRange(tempList); 
     } 
     // Find out if there are enough left that it's asking for 
     uint toGenerate = System.Math.Min(count, _numLeft); 

     // Wait for load 
     _numLeft = await _loadMore(toGenerate); 

     // This code simply generates 
     var values = from j in Enumerable.Range((int)_count, (int)toGenerate) 
        select (object)_generator(j); 
     _count += toGenerate; 

     return values.ToList().AddRange(tempList); 
    } 

    protected override bool HasMoreItemsOverride() 
    { 
     return _numLeft > 0; 
    } 


    Func<int, T> _generator; 
    uint _count = 0; 
    uint _maxCount; 

} 

然後你就這樣使用它。

// Move these outside of the loop 
entriesCVS.Source = App.EntriesViewModel.entries; 
App.EntriesViewModel.entries = new GeneratorIncrementalLoadingClass<Entry>(App.EntriesViewModel.LoadEntries, (index) => 
{ 
    return App.EntriesViewModel.EntriesOc.ElementAt(index); 
}); 

什麼應該現在發生的是它設置CollectionViewSource開宗明義,然後將數據加載到基地集合(您EntriesOc)懶洋洋地。當ListView滾動到底部時,它應該自動調用LoadMoreItemsOverrideAsync。這將做的是調用你的異步加載函數並存儲響應(可以加載的數字)。然後它能夠​​根據該響應通知ListView是否有剩餘物品。

你之前在做什麼,在懶洋洋的,而不是增量開始加載該項目的所有(以塊的形式,基於什麼用戶目前正在做。

這個解決方案仍然是不完美的。如果用戶非常快速地向下滾動並且依次加載所有內容,那麼會出現問題(我試圖說明問題),理想情況是如果您的後臺加載功能可以接受一系列優先加載的項目,在最後的會首先加載,而不必等待列表的其餘部分加載。

不管怎樣,希望幫助和快樂的編碼!

相關問題