AdvancedCollectionView实现ISupportIncrementalLoading接口,但它不起作用

时间:2018-05-15 17:30:35

标签: c# xaml uwp-xaml windows-community-toolkit

UWP社区工具包(现在称为Windows社区工具包)AdvancedCollectionView集合实现了ISupportIncrementalLoading接口,因此我尝试将其与ListView一起使用,一次只加载部分项目,但ListView仍然加载所有项目立刻。我错过了什么?

这是XAML:

<ListView x:Name="MyListView"
    DataFetchSize="10"
    IncrementalLoadingTrigger="Edge"
    IncrementalLoadingThreshold="10"
    ItemSource="{x:Bind ACV, Mode=TwoWay}">
</ListView>

以下是代码隐藏:

public class MainPage
{
    public AdvancedCollectionView ACV { get; set; }
    // Lets say that DocCollection contains 1000 items
    public ObservableCollection<Document> DocCollection;

    public MainPage()
    {
        ACV = new AdvancedCollectionView(DocCollection, true);
    }
}

1 个答案:

答案 0 :(得分:0)

AdvancedCollectionView是一个集合视图实现,支持过滤,排序和增量加载。但根据我链接的文件的用法部分,

  

增量加载:如果您的源集合支持该功能,那么AdvancedCollectionView也会这样做(它只是转发调用)

因此AdvancedCollectionView本身没有增量功能,所以它可以简单地转发呼叫。这意味着您为AdvancedCollectionView提供的源集合应该从ISupportIncrementalLoading接口继承。此外,如果您检查AdvancedCollectionView.LoadMoreItemsAsync方法,则会显示尚未实现,表明AdvancedCollectionView未实现ISupportIncrementalLoading接口。

在您的情况下,您只需使用ObservableCollection作为默认情况下不支持ISupportIncrementalLoading的源集合。要创建支持增量加载的集合视图,请参阅此official sample

DocCollection = new GeneratorIncrementalLoadingClass<DataTest>(1000, (count) =>
{
    return new DataTest() { Country = "Ghana" + count, City = "Wa" + count };
});
DocCollection.CollectionChanged += DocCollection_CollectionChanged;
ACV = new AdvancedCollectionView(DocCollection, true);
MyListView.ItemsSource = ACV;

public class GeneratorIncrementalLoadingClass<T> : 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;
    }

    #region State

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

    #endregion 
}

public abstract class IncrementalLoadingBase : IList, ISupportIncrementalLoading, INotifyCollectionChanged
{
    #region IList

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

    #endregion

    #region ISupportIncrementalLoading

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

    #endregion 

    #region INotifyCollectionChanged

    public event NotifyCollectionChangedEventHandler CollectionChanged;

    #endregion 

    #region Private methods

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

    #endregion

    #region Overridable methods

    protected abstract Task<IList<object>> LoadMoreItemsOverrideAsync(CancellationToken c, uint count);
    protected abstract bool HasMoreItemsOverride();

    #endregion 

    #region State

    List<object> _storage = new List<object>();
    bool _busy = false;

    #endregion 
}