5

I'm trying to create a Win8 Metro reference app for virtualized lists. In doing some (very sparse) reading, I've found that the recommended way of supporting this is through the ISupportIncrementalLoading interface.

I'm having a problem with my reference app, where the LoadMoreItemsAsync method is called once, but isn't called again, even though my HasmoreItems property is hard coded to return True.

What the code below should do is load 40 items, then load 'x' number at a time afterwards. What happens is that it loads the first 40 items, then is prompted to load 42 more, then is never asked to load again.

Here's the relevant portions of my code:

XAML

<Grid Background="{StaticResource ApplicationPageBackgroundBrush}">
    <ListView ItemsSource="{Binding Items}" Width="800" HorizontalAlignment="Left" Margin="12">
        <ListView.ItemTemplate>
            <DataTemplate>
                <TextBlock Text="{Binding Title}" Foreground="White"/>
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>

</Grid>

ViewModel and Support Classes:

public class MainViewModel : ViewModelBase
{

    public MyIncrementalCollection Items { get; set; }

    public MainViewModel()
    {

        Items = new MyIncrementalCollection();



        for (int i = 0; i < 40; i++)
        {
            Items.Add(new MyData {Title = string.Format("Item: {0}", i)});
        }
    }
}

public class MyData
{
    public string Title { get; set; }
}

public class MyIncrementalCollection : ObservableCollection<MyData>, ISupportIncrementalLoading
{
    public bool HasMoreItems
    {
        get
        {
            return true;
        }
    }

    public IAsyncOperation<LoadMoreItemsResult> LoadMoreItemsAsync(uint count)
    {
        return
            (IAsyncOperation<LoadMoreItemsResult>)
            AsyncInfo.Run((System.Threading.CancellationToken ct) => LoadDataAsync(count));
    }

    private async Task<LoadMoreItemsResult> LoadDataAsync(uint count)
    {

        for (int i = 0; i < count; i++)
        {
            this.Add(new MyData { Title = string.Format("Item: {0}, {1}", i, System.DateTime.Now) });
        }

        var ret = new LoadMoreItemsResult {Count = count};

        return ret;
    }


}

}

Filip Skakun
  • 31,624
  • 6
  • 74
  • 100
Robaticus
  • 22,857
  • 5
  • 54
  • 63

2 Answers2

2

The problem is that your method LoadDataAsync(uint count) is lacking the await operator and due to that it will run synchronously. I had a similar problem. Data virtualization was working for me while I was receiving some library folders but it was triggered only once when I tried to load a collection of custom items.

I used a workaround, not very elegant but it worked. Modify your LoadDataAsync method like this:

private async Task<LoadMoreItemsResult> LoadDataAsync(uint count)
{
  Task task = Task.Delay( 1 );
  await task;

  for (int i = 0; i < count; i++)
  {
    Add(new MyData { Title = string.Format("Item: {0}, {1}", i, System.DateTime.Now) });
  }

  return new LoadMoreItemsResult {Count = count};
}
Sven Meyer
  • 36
  • 3
0

The UI will only call HasMoreItems when it feels it needs to. If it has enough items to fill the currently viewable area then it won't check for more items. If you start to scroll towards the end of the list then it will check to see if there are more items (and if there are call LoadMoreItemsAsync).

As an aside you can simplify your code in LoadMoreItemsAsync to

public IAsyncOperation<LoadMoreItemsResult> LoadMoreItemsAsync(uint count)
{
    return LoadDataAsync(count).AsAsyncOperation();
}
Nigel Sampson
  • 10,549
  • 1
  • 28
  • 31
  • Thanks for the simplification. The problem here is that, as I scroll, the load only gets called once. I can make it all the way to the bottom of the list, after the first load of additional items, and it never fires again. – Robaticus May 10 '12 at 10:56
  • Ok, is the xaml the entirety of your view? Other problems can include if you have your ListView inside a ScrollViewer you won't get data virtualisation triggers (since it depends on using the List Views internal ScrollViewer). – Nigel Sampson May 10 '12 at 11:06
  • That's the entirety, with the exception of the enclosing `` tag. Do I have to do anything specific in my asynchronous loading action to tell the ListView that I'm done loading, so it doesn't fire again? I assumed the return of the LoadMoreItemsResult would be all that it really needed. – Robaticus May 10 '12 at 11:34
  • Can you try it with no items initially loaded? I vaguely recall that I had a similar problem, and I believe that was the solution. – wilbur4321 May 11 '12 at 21:07