ISupportIncrementalLoading Collection - 在 LoadingMoreItems 正在进行时通知 UI

Posted

技术标签:

【中文标题】ISupportIncrementalLoading Collection - 在 LoadingMoreItems 正在进行时通知 UI【英文标题】:ISupportIncrementalLoading Collection - notify UI when LoadingMoreItems is in progress 【发布时间】:2015-03-08 08:03:31 【问题描述】:

我在我的应用中创建了一个IncrementalLoadingCollection 类,它实现了ISupportIncrementalLoading 并继承自ObservableCollection< T >

它工作正常并且项目已加载,但我想在应用程序的Status Bar 上显示一条消息,说明正在进行一些工作。

实现这一目标的好方法是什么?

由于滚动列表时在内部调用LoadMoreItemsAsync,因此我无法访问该部分以提供更新Status Bar 的代码。现在,我在LoadMoreItemsAsync 中执行此操作,我发现这是一种糟糕的方法,但到目前为止我找不到更好的方法...

非常感谢任何建议。

【问题讨论】:

【参考方案1】:

例如,您可以:从ObservableCollection 继承并像这样实现ISupportIncrementalLoading

class IncrementalLoadingObservableCollection<T> : ObservableCollection<T>, ISupportIncrementalLoading

    private readonly Func<CancellationToken, Task<IEnumerable<T>>> _provideMoreItems;

    public IncrementalLoadingObservableCollection(Func<CancellationToken, Task<IEnumerable<T>> provideMoreItems)
    
        _provideMoreItems = provideMoreItems;
    

    public IAsyncOperation<LoadMoreItemsResult> LoadMoreItemsAsync(uint count)
    
        return AsyncInfo.Run(async cancelToken =>
        
            await Window.Current.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
            
                OnLoadMoreItemsStarted();
            );

            var providedItems = await _provideMoreItems(cancelToken);

            await Window.Current.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
            
                foreach(var item in providedItems)
                    Add(item);

                OnLoadMoreItemsCompleted();
            );

            return new LoadMoreItemsResult Count = (uint) providedItems.Count();;
        );
    

    public bool HasMoreItems
    
        get  return true; 
    

    public event Action LoadMoreItemsStarted;
    public event Action LoadMoreItemsCompleted;

    protected virtual void OnLoadMoreItemsStarted()
    
        var handler = LoadMoreItemsStarted;
        if (handler != null) handler();
    

    protected virtual void OnLoadMoreItemsCompleted()
    
        var handler = LoadMoreItemsCompleted;
        if (handler != null) handler();
    

如何使用它?在您的 ViewModel 中:

class MyFancyItemsViewModel

     public MyFancyItemsViewModel()
       
         var incrementalObservablCollcetion = new IncrementalLoading...(GetItemsFromInternetOrSmth);
         incrementalObservablCollcetion.LoadMoreItemsStarted += OnItemsLoadingStarted;
         incrementalObservablCollcetion.LoadMoreItemsCompleted += OnItemsLoadingCompleted;

          ItemsBindedInXaml = incrementalObservablCollcetion;
     

     private Task<IEnumerable<Items>> GetItemsFromInternetOrSmth(CancellationToken cancelToken)
     
      ... do some work returns enumerable of Items
     

     private void OnItemsLoadingStarted()
      .. do smth .. 

     private void OnItemsLoadingCompleted()
      ... do smth ..  

     public ObservableCollection<Items> ItemsBindedInXaml  get; private set; 

你可能会问我为什么在IncrementalLoadingObservableCollection 中使用Dispatcher.RunAsync - 原因是LoadMoreItemsAsync 可能在另一个线程上运行(不知道)所以你必须将所有工作分派给UI Thread (不使用Dispatcher,就不能从UI thread以外的线程调用UI相关的方法)。

如果您觉得 ViewModel 不适合 UI 相关操作,请查看一些消息传递机制(如 MVVM Light Messenger,在代码隐藏中注册消息并在 LoadMoreItemsStarted 处理程序中发送此消息)

【讨论】:

这种使用事件的方式非常棒,我喜欢!我已经在使用调度程序返回带有消息的 UI,但由于糟糕的耦合,我一点也不满意。如果我能多次投票这个答案就好了:)非常感谢! 通知似乎只发生一次,在第一次通话时......我已经进行了编辑。处理程序中的代码在断点被命中时执行,但 UI 上没有显示任何内容... @VasileF 这不是与 IncrementalObservableCollection 相关的错误 - 当 OnCompleted 被调用时,“StatusBar.HideAsync”被调用(根据您的代码),这意味着 StatusBar 将被关闭,直到您调用“StatusBar.ShowAsync”。所以你需要调用:await statusBar.ShowAsync();在显示进度指示器之前 @Vasilef 我宁愿在 Completed 事件处理程序中使用 StatusBar.ProgressIndicator.HideAsync。

以上是关于ISupportIncrementalLoading Collection - 在 LoadingMoreItems 正在进行时通知 UI的主要内容,如果未能解决你的问题,请参考以下文章