在滚动结束创建LoadMoreItemsAsync一个ListView [英] Create a ListView with LoadMoreItemsAsync on end of scroll

查看:372
本文介绍了在滚动结束创建LoadMoreItemsAsync一个ListView的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在我的Windows Phone 8.1的应用程序有一个的ListView ,我可以有一些像1000以上的成绩,所以我每次都需要实现加载更多功能的滚动触底,或其他一些逻辑和触发更多的项目到列表中添加的自然方式。结果
我发现的ListView 有一个用于支持 ISupportIncrementalLoading ,并发现此实现:<一href=\"https://marcominerva.word$p$pss.com/2013/05/22/implementing-the-isupportincrementalloading-interface-in-a-window-store-app/\">https://marcominerva.word$p$pss.com/2013/05/22/implementing-the-isupportincrementalloading-interface-in-a-window-store-app/
这是更好的解决方案,我发现,因为它没有指定类型,即,它是通用的。结果

I have a ListView in my Windows Phone 8.1 application and I can have something like 1000 or more results, so I need to implement a Load More feature each time the scroll hits bottom, or some other logic and natural way of triggering the adding of more items to the List.
I found that the ListView has support for an ISupportIncrementalLoading, and found this implementation: https://marcominerva.wordpress.com/2013/05/22/implementing-the-isupportincrementalloading-interface-in-a-window-store-app/ This was the better solution I found, since it does not specify a type, i.e., it's generic.

我的这个解决方案的问题是,当在ListView被加载, LoadMoreItemsAsync 运行,直到需要它得到了所有的结果,这意味着负载更不是所有时间由用户触发。我不知道是什么让 LoadMoreItemsAsync 触发,但东西是不正确的,因为它假定发生在我打开网页,并加载在现场的所有项目,没有我做任何事或任何滚动。这里的实现:结果
IncrementalLoadingCollection.cs

My problem with this solution is that when the ListView is Loaded, the LoadMoreItemsAsync runs all the times needed until it got all the results, meaning that the Load More is not triggered by the user. I'm not sure what make the LoadMoreItemsAsync trigger, but something is not right, because it assumes that happens when I open the page and loads all items on the spot, without me doing anything, or any scrolling. Here's the implementation:
IncrementalLoadingCollection.cs

public interface IIncrementalSource<T> {
    Task<IEnumerable<T>> GetPagedItems(int pageIndex, int pageSize);
    void SetType(int type);
}

public class IncrementalLoadingCollection<T, I> : ObservableCollection<I>, ISupportIncrementalLoading where T : IIncrementalSource<I>, new() {
    private T source;
    private int itemsPerPage;
    private bool hasMoreItems;
    private int currentPage;

    public IncrementalLoadingCollection(int type, int itemsPerPage = 10) {
        this.source = new T();
        this.source.SetType(type);
        this.itemsPerPage = itemsPerPage;
        this.hasMoreItems = true;
    }

    public bool HasMoreItems {
        get { return hasMoreItems; }
    }

    public IAsyncOperation<LoadMoreItemsResult> LoadMoreItemsAsync(uint count) {
        var dispatcher = Window.Current.Dispatcher;

        return Task.Run<LoadMoreItemsResult>(
            async () => {
                uint resultCount = 0;
                var result = await source.GetPagedItems(currentPage++, itemsPerPage);

                if(result == null || result.Count() == 0) {
                    hasMoreItems = false;
                }
                else {
                    resultCount = (uint)result.Count();

                    await dispatcher.RunAsync(
                        CoreDispatcherPriority.Normal,
                        () => {
                            foreach(I item in result)
                                this.Add(item);
                        });
                }

                return new LoadMoreItemsResult() { Count = resultCount };

            }).AsAsyncOperation<LoadMoreItemsResult>();
    }
}

这里的 PersonModelSource.cs

public class DatabaseNotificationModelSource : IIncrementalSource<DatabaseNotificationModel> {
    private ObservableCollection<DatabaseNotificationModel> notifications;
    private int _type = "";

    public DatabaseNotificationModelSource() {
        //
    }

    public void SetType(int type) {
        _type = type;
    }

    public async Task<IEnumerable<DatabaseNotificationModel>> GetPagedItems(int pageIndex, int pageSize) {
        if(notifications == null) {
            notifications = new ObservableCollection<DatabaseNotificationModel>();
            notifications = await DatabaseService.GetNotifications(_type);
        }

        return await Task.Run<IEnumerable<DatabaseNotificationModel>>(() => {
            var result = (from p in notifications select p).Skip(pageIndex * pageSize).Take(pageSize);
                return result;
            });
    }
}

我改了一点,因为调用我的数据库是异步的,这是我发现的,以确保我能灌收集之前等待查询的唯一途径。
搜索结果
在我的 DatabaseNotificationViewModel.cs

IncrementalNotificationsList = new IncrementalLoadingCollection<DatabaseNotificationModelSource, DatabaseNotificationModel>(type);

结果
一切工作正常,除了不那么正常的加载更多。什么是错误的,我code?


Everything works fine, apart from the not so normal "Load More". What's wrong in my code?

推荐答案

我创造了这个问题的非常简单的例子这里,并提出在MSDN论坛上这个问题<一href=\"https://social.msdn.microsoft.com/Forums/windowsapps/en-US/dc1e1fe2-6b4e-400d-a66a-d116b47f6047/isupportincrementalloading-listview-loads-too-many-items-only-when-performing-an-async-operation-in?forum=winappswithcsharp#dc1e1fe2-6b4e-400d-a66a-d116b47f6047\">here.老实说,我不知道为什么这种怪异的行为发生。

I created a very simplified example of this issue here, and raised this issue on the MSDN forums here. Honestly, I don't know why this weird behavior is happening.

我观察到什么


  • ListView控件将调用 LoadMoreItemsAsync 先用1计数我认为这是决定一个项目的大小,使其能够制定出的项目数请求下一次调用。

  • 如果ListView控件是很好的表现,为 LoadMoreItemsAsync 第二个电话,应立即在第一次调用之后发生,但用正确的项目数(计数> 1),再没有更多的调用 LoadMoreItemsAsync 将除非你向下滚动出现。在你的榜样,但是,它可能会错误地称之为 LoadMoreItemsAsync 为1的再次的计数。

  • 在最坏的情况下,这实际上在你的例子出现相当频繁,是在ListView将继续一遍又一遍拨打 LoadMoreItemsAsync 为1的数,为了直到 HasMoreItems 为假,在这种情况下,它加载的所有项目的一次。发生这种情况时,有一个明显的界面延迟,而在ListView加载的项目。 的UI线程没有被阻塞,虽然。 ListView控件只是占用与顺序调用UI线程 LoadMoreItemsAsync

  • ListView控件不会总是用尽所有的项目虽然。有时它会加载100,或200,或500个项目。在每种情况下,该模式是: LoadMoreItemsAsync(1)其次为单个呼叫LoadMoreItemsAsync许多电话(大于1)如果不是所有的项目已被现有的呼叫加载。

  • 它似乎只在页面加载时发生。

  • 的问题是在Windows Phone 8.1和Windows 8.1执着。

  • The ListView will call LoadMoreItemsAsync first with a count of 1. I assume this is to determine the size of a single item so that it can work out the number of items to request for the next call.
  • If the ListView is behaving nicely, the second call to LoadMoreItemsAsync should happen immediately after the first call, but with the correct number of items (count > 1), and then no more calls to LoadMoreItemsAsync will occur unless you scroll down. In your example, however, it may incorrectly call LoadMoreItemsAsync with a count of 1 again.
  • In the worst case, which actually occurs quite frequently in your example, is that the ListView will continue to call LoadMoreItemsAsync with a count of 1 over and over, in order, until HasMoreItems becomes false, in which case it has loaded all of the items one at a time. When this happens, there is a noticeable UI delay while the ListView loads the items. The UI thread isn't blocked, though. The ListView is just hogging the UI thread with sequential calls to LoadMoreItemsAsync.
  • The ListView won't always exhaust all of the items though. Sometimes it will load 100, or 200, or 500 items. In each case, the pattern is: many calls of LoadMoreItemsAsync(1) followed by a single call to LoadMoreItemsAsync(> 1) if not all of the items have been loaded by the prior calls.
  • It only seems to occur on page load.
  • The issue is persistent on Windows Phone 8.1 as well as Windows 8.1.

是什么原因导致的问题


  • 的问题似乎很短暂的等待任务 LoadMoreItemsAsync 方法之前您添加的项目清单(等待任务您添加的项目列表后是罚款)。

  • 如果您删除所有等待的内线 LoadMoreItemsAsync 不会发生此​​问题,这样就可以迫使同步执行。特别是,如果你删除 dispatcher.RunAsync 包装和等待source.GetPagedItems (只是嘲笑中的项目),那么在ListView会表现很好。

  • 已经删除了所有等待 s时,问题将再次出现,即使你添加一个看似无害的等待Task.Run(()=&GT ; {})。如何离奇!

  • The issue seems to be very short lived awaited tasks in the LoadMoreItemsAsync method before you've added the items to the list (awaiting tasks after you've added the items to the list is fine).
  • The issue doesn't occur if you remove all awaits inside LoadMoreItemsAsync, thus forcing it to execute synchronously. Specifically, if you remove the dispatcher.RunAsync wrapper and await source.GetPagedItems (just mock the items instead), then the ListView will behave nicely.
  • Having removed all awaits, the issue will reappear even if all you add is a seemingly harmless await Task.Run(() => {}). How bizarre!

如何来解决这个问题

如果大部分在 LoadMoreItemsAsync 通话所花费的时间正在等待对项目的下一个页面的HTTP请求,因为我希望大多数应用程序是,那么问题获得'T发生。因此,我们可以通过延长等待的方法所花费的时间 Task.Delay(10),这样也许:

If most of the time spent in a LoadMoreItemsAsync call is waiting for a HTTP request for the next page of items, as I expect most apps are, then the issue won't occur. So, we can extend the time spent in the method by awaiting a Task.Delay(10), like this maybe:

await Task.WhenAll(Task.Delay(10), dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
    foreach (I item in result)
        this.Add(item);
}).AsTask());


我只是提供了一个(哈克)解决方法你的榜样,但不能解释为什么。 如果有人知道为什么发生这种情况,请让我知道。

这篇关于在滚动结束创建LoadMoreItemsAsync一个ListView的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆