Skip to content

Instantly share code, notes, and snippets.

@dotMorten
Last active November 17, 2017 00:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dotMorten/1b9b00dea1dcd94df45e1bd4ef30c980 to your computer and use it in GitHub Desktop.
Save dotMorten/1b9b00dea1dcd94df45e1bd4ef30c980 to your computer and use it in GitHub Desktop.
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Threading.Tasks;
using Windows.Foundation;
using Windows.UI.Core;
using Windows.UI.Xaml.Data;
namespace UniversalTestApp
{
public class TestClass
{
public async void Test()
{
IncrementalList<int> list = new IncrementalList<int>(async (count, offset) =>
{
await Task.Delay(1000); //Simulate delay
//Replace this stuff with proper database queries
List<int> results = new List<int>();
for (int i = offset; i < offset + count; i++)
{
results.Add(i);
}
return results;
});
}
}
public class IncrementalList<T> : ObservableCollection<T>, ISupportIncrementalLoading
{
private Func<int, int, Task<List<T>>> _loadMoreAction;
public IncrementalList(IList<T> items, Func<int, int, Task<List<T>>> loadMoreAction) : this(loadMoreAction)
{
foreach (var item in items)
Items.Add(item);
}
public IncrementalList(Func<int, int, Task<List<T>>> loadMoreAction)
{
if (loadMoreAction == null)
throw new ArgumentNullException(nameof(loadMoreAction));
_loadMoreAction = loadMoreAction;
}
IAsyncOperation<LoadMoreItemsResult> ISupportIncrementalLoading.LoadMoreItemsAsync(uint count)
{
return ProcessMoreAsync(count).AsAsyncOperation();
}
private async Task<LoadMoreItemsResult> ProcessMoreAsync(uint count)
{
var items = await _loadMoreAction((int)count, Count).ConfigureAwait(false);
var results = items?.Count ?? 0;
HasMoreItems = results >= count;
if (results > 0)
{
// Ensure we update the list on the UI thread
await Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal,
() =>
{
int oldCount = this.Count;
foreach (var item in items)
base.Items.Add(item);
base.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, changedItems: items, startingIndex: oldCount));
base.OnPropertyChanged(new System.ComponentModel.PropertyChangedEventArgs(nameof(Count)));
base.OnPropertyChanged(new System.ComponentModel.PropertyChangedEventArgs("Items[]"));
});
}
return new LoadMoreItemsResult() { Count = (uint)results };
}
public bool HasMoreItems { get; private set; } = true;
}
}
@dotMorten
Copy link
Author

This implementation is a little more complex than needed, but it adds a few extra optimizations: It uses the protected Items collection to add items, which doesn't raise an event for each Add, then raises a single event at the end for all the items.
It also tries to do as much as possible on the background thread, and only update the collection itself on the UI Thread.

@rpairo
Copy link

rpairo commented Nov 16, 2017

I change:

        `IncrementalList<int> list = new IncrementalList<int>(async (count, offset) => {
            await Task.Delay(1000);

            List<int> results = new List<int>();
            for (int i = 0; i < count; i++)
            {
                results.Add(count);
            }
            return results;
        });`

for:

        `IncrementalList<Protocolos> list = new IncrementalList<Protocolos>(async (count, offset) =>
        {
            // await Task.Delay(1000); //Simulate delay
            // Replace this stuff with proper database queries
            List<Protocolos> results = new List<Protocolos>();

            Task t = Facade.PoblarListaProtocolos(results, tablaProtocolo, textoFiltro, tipoFiltro);
            await t;

            /*for (int i = 0; i < count; i++)
            {
                results.Add(count);
            }*/ 
            return results;
        });`

But not work...

@dotMorten
Copy link
Author

dotMorten commented Nov 16, 2017

Is the 'results' list getting populated?
On a side-note It might be cleaner if PoblarListaProtocols returns Task<List<Protocols>> instead of just Task.
List<Protocols> results = await Facade.PoblarListaProtocolos(tablaProtocolo, textoFiltro, tipoFiltro);

Also define 'not work'. I'm terrible at guessing

@dotMorten
Copy link
Author

Just realize this condition is also wrong? HasMoreItems = results < count;
Should be HasMoreItems = results == count

@dotMorten
Copy link
Author

dotMorten commented Nov 17, 2017

Another thing I just noticed: You never use the count and offset values that are passed into the delegate. Your query method PoblarListaProtocolos needs to take these parameters. Ie the two parameters will tell you "get the next 50 items, starting at offset 100"

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment