ISupportIncrementalLoading 在离开后不会停止
ISupportIncrementalLoading doesn't stop after navigating away
突然发现实现ISupportIncrementalLoading的集合有一个奇怪的行为。
假设我们有一个主页,其中 ISupportIncrementalLoading 集合绑定到 ListView。我们还有另一个可以导航到的页面。
导航到主页时,ISupportIncrementalLoading 开始加载项目,直到 ListView 认为足够为止。在 ListView 加载它需要的所有项目之前,我导航到新页面。
我的预期行为:ListView 停止加载新项目,因为页面现在不可见。
真实行为:ListView 继续无休止地加载项目,即使在离开页面后也是如此。直到获得 HasMore == false 才会停止。
有人能帮忙吗?这绝对是错误的行为。
PS
如果我在导航时,在 ViewModel 中将集合设置为 null,然后在返回时将其恢复——这似乎很有帮助,但我认为这样做太多了。
这是我的基本 ISupportIncrementalLoading 集合的代码:
public abstract class BaseIncrementalSupportCollection<T> :IList<T>,IList,INotifyCollectionChanged, ISupportIncrementalLoading, INotifyPropertyChanged
{
protected readonly List<T> storage;
private bool isLoading;
public bool IsLoading
{
get
{
return isLoading;
}
set
{
if (isLoading != value)
{
isLoading = value;
RaisePropertyChanged();
}
}
}
public bool failed;
public bool IsFailed
{
get { return failed; }
set
{
if (failed != value)
{
failed = value;
RaisePropertyChanged();
}
}
}
public bool IsEmpty
{
get { return !HasMoreItems && Count == 0; }
}
protected BaseIncrementalSupportCollection()
{
storage = new List<T>();
}
public virtual IAsyncOperation<LoadMoreItemsResult> LoadMoreItemsAsync(uint count)
{
return Task.Run(()=>LoadMoreItems(count)).AsAsyncOperation();
}
public abstract bool HasMoreItems { get; }
private async Task<LoadMoreItemsResult> LoadMoreItems(uint count)
{
IsLoading = true;
IsFailed = false;
try
{
var items = await LoadMoreItemsOverride(count);
if (items == null)
return new LoadMoreItemsResult() {Count = 0};
if (items.Count > 0)
{
var prevEmptyState = IsEmpty;
foreach (var item in items)
{
var currItem = item;
await DispatchHelper.RunOnUiIfNecessary(async () =>
{
storage.Add(currItem);
RaiseCollectionChanged(
new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, currItem,
storage.Count - 1));
});
}
if(prevEmptyState!=IsEmpty)
RaisePropertyChanged("IsEmpty");
}
return new LoadMoreItemsResult() {Count = (uint) items.Count};
}
catch (Exception e)
{
var aggregate = e as AggregateException;
if (aggregate != null)
e = aggregate.Flatten().InnerException;
IsFailed = true;
var handler = OnError;
if (handler != null)
DispatchHelper.RunOnUiIfNecessary(
() => handler(this, new IncrementallCollectionLoadErrorEventArgs(e)));
return new LoadMoreItemsResult() {Count = 0};
}
finally
{
IsLoading = false;
}
}
protected virtual void RaiseCollectionChanged(NotifyCollectionChangedEventArgs e)
{
if (CollectionChanged != null)
CollectionChanged(this, e);
}
protected abstract Task<IList<T>> LoadMoreItemsOverride(uint count);
[NotifyPropertyChangedInvocator]
protected virtual void RaisePropertyChanged([CallerMemberName] string propertyName = null)
{
var handler = PropertyChanged;
if (handler != null)
DispatchHelper.RunOnUiIfNecessary(()=>handler(this, new PropertyChangedEventArgs(propertyName)));
}
public event PropertyChangedEventHandler PropertyChanged;
public event EventHandler<IncrementallCollectionLoadErrorEventArgs> OnError;
public event NotifyCollectionChangedEventHandler CollectionChanged;
}
我刚刚找到了另一种方法,添加额外的 bool 字段 isStopped 方法 Start,ForceStop 将其设置为 false/true。这个值在获取 HasMoreItems 时使用
bool HasMoreItems{get{return !isStopped && DetermineIfHasMore()};}
只需调用这些方法,我就可以停止或继续加载同一个集合生成器。
突然发现实现ISupportIncrementalLoading的集合有一个奇怪的行为。 假设我们有一个主页,其中 ISupportIncrementalLoading 集合绑定到 ListView。我们还有另一个可以导航到的页面。 导航到主页时,ISupportIncrementalLoading 开始加载项目,直到 ListView 认为足够为止。在 ListView 加载它需要的所有项目之前,我导航到新页面。 我的预期行为:ListView 停止加载新项目,因为页面现在不可见。 真实行为:ListView 继续无休止地加载项目,即使在离开页面后也是如此。直到获得 HasMore == false 才会停止。 有人能帮忙吗?这绝对是错误的行为。
PS
如果我在导航时,在 ViewModel 中将集合设置为 null,然后在返回时将其恢复——这似乎很有帮助,但我认为这样做太多了。
这是我的基本 ISupportIncrementalLoading 集合的代码:
public abstract class BaseIncrementalSupportCollection<T> :IList<T>,IList,INotifyCollectionChanged, ISupportIncrementalLoading, INotifyPropertyChanged
{
protected readonly List<T> storage;
private bool isLoading;
public bool IsLoading
{
get
{
return isLoading;
}
set
{
if (isLoading != value)
{
isLoading = value;
RaisePropertyChanged();
}
}
}
public bool failed;
public bool IsFailed
{
get { return failed; }
set
{
if (failed != value)
{
failed = value;
RaisePropertyChanged();
}
}
}
public bool IsEmpty
{
get { return !HasMoreItems && Count == 0; }
}
protected BaseIncrementalSupportCollection()
{
storage = new List<T>();
}
public virtual IAsyncOperation<LoadMoreItemsResult> LoadMoreItemsAsync(uint count)
{
return Task.Run(()=>LoadMoreItems(count)).AsAsyncOperation();
}
public abstract bool HasMoreItems { get; }
private async Task<LoadMoreItemsResult> LoadMoreItems(uint count)
{
IsLoading = true;
IsFailed = false;
try
{
var items = await LoadMoreItemsOverride(count);
if (items == null)
return new LoadMoreItemsResult() {Count = 0};
if (items.Count > 0)
{
var prevEmptyState = IsEmpty;
foreach (var item in items)
{
var currItem = item;
await DispatchHelper.RunOnUiIfNecessary(async () =>
{
storage.Add(currItem);
RaiseCollectionChanged(
new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, currItem,
storage.Count - 1));
});
}
if(prevEmptyState!=IsEmpty)
RaisePropertyChanged("IsEmpty");
}
return new LoadMoreItemsResult() {Count = (uint) items.Count};
}
catch (Exception e)
{
var aggregate = e as AggregateException;
if (aggregate != null)
e = aggregate.Flatten().InnerException;
IsFailed = true;
var handler = OnError;
if (handler != null)
DispatchHelper.RunOnUiIfNecessary(
() => handler(this, new IncrementallCollectionLoadErrorEventArgs(e)));
return new LoadMoreItemsResult() {Count = 0};
}
finally
{
IsLoading = false;
}
}
protected virtual void RaiseCollectionChanged(NotifyCollectionChangedEventArgs e)
{
if (CollectionChanged != null)
CollectionChanged(this, e);
}
protected abstract Task<IList<T>> LoadMoreItemsOverride(uint count);
[NotifyPropertyChangedInvocator]
protected virtual void RaisePropertyChanged([CallerMemberName] string propertyName = null)
{
var handler = PropertyChanged;
if (handler != null)
DispatchHelper.RunOnUiIfNecessary(()=>handler(this, new PropertyChangedEventArgs(propertyName)));
}
public event PropertyChangedEventHandler PropertyChanged;
public event EventHandler<IncrementallCollectionLoadErrorEventArgs> OnError;
public event NotifyCollectionChangedEventHandler CollectionChanged;
}
我刚刚找到了另一种方法,添加额外的 bool 字段 isStopped 方法 Start,ForceStop 将其设置为 false/true。这个值在获取 HasMoreItems 时使用
bool HasMoreItems{get{return !isStopped && DetermineIfHasMore()};}
只需调用这些方法,我就可以停止或继续加载同一个集合生成器。