奇妙に聞こえるかもしれませんが、私はISupportIncrementalLoadingを使用することはMVVMのビューレイヤ用であることを知っています。MVVMでISupportIncrementalLoadingを使用する場合のベストプラクティスは何ですか?
ViewModelでコレクションプロパティが更新されるたびに、xaml.csでListViewのアイテムソースを更新しています。このようなニーズのための他の(そしてより良い)ソリューションがありますか?
奇妙に聞こえるかもしれませんが、私はISupportIncrementalLoadingを使用することはMVVMのビューレイヤ用であることを知っています。MVVMでISupportIncrementalLoadingを使用する場合のベストプラクティスは何ですか?
ViewModelでコレクションプロパティが更新されるたびに、xaml.csでListViewのアイテムソースを更新しています。このようなニーズのための他の(そしてより良い)ソリューションがありますか?
こんにちは私はMVVMパターンを何度も使用してISupportIncrementalLoadingを使用しています。
すべてのデータをロードするためのすべてのロジックをカプセル化する独立したクラスを作成したいと思います。ここで私のクラスの1つの例を示します。
私はすべてのカスタムコレクションのすべてのコードを再利用するためにIncrementalCollectionBaseを作成しました。
public class IncrementalCollectionBase<T> : ObservableCollection<T>,
ISupportIncrementalLoading,
INotifyPropertyChanged,
IIncrementalCollection<T>, IDisposable
{
private long totalRecordCount;
public int PageNo { get; set; }
public int PageSize { get; set; }
public int PageCount { get; set; }
public long TotalRecordCount
{
get
{
return this.totalRecordCount;
}
set
{
this.totalRecordCount = value;
OnPropertyChanged(new PropertyChangedEventArgs("TotalRecordCount"));
}
}
public IncrementalCollectionBase()
{
this.FeedSize = 10;
}
public CancellationTokenSource CancelToken { get; set; }
public bool HasMoreItems { get; set; }
private bool isLoading { get; set; }
public bool IsLoading
{
get
{
return isLoading;
}
set
{
isLoading = value;
OnPropertyChanged(new PropertyChangedEventArgs("IsLoading"));
}
}
public int FeedSize { get; set; }
public event EventHandler<LoadIncrementalCollectionChanged> OnLoadIncrementalCollectionChanged;
public void Cancel()
{
try
{
CancelToken?.Cancel();
}
catch (Exception ex)
{
}
}
public virtual Task<IEnumerable<T>> LoadDataAsync()
{
throw new NotImplementedException();
}
public virtual IAsyncOperation<LoadMoreItemsResult> LoadMoreItemsAsync(uint count)
{
throw new NotImplementedException();
}
public virtual void Setup(CancellationTokenSource cancelToken = null)
{
CancelToken = cancelToken;
}
public void Dispose()
{
try
{
Cancel();
Items.Clear();
}
catch (Exception)
{
}
}
}
これを行うの後、私は私のカスタムコレクション
public class MyCustomEntityIncrementalCollection : IncrementalCollectionBase<CustomEntity>
{
private ISearchentityService searchentityService = null;
private bool searchMode = false;
private string key = "";
private bool IsFirstSearchResult = true;
private IentityService entityService = null;
private ILoginService loginService = null;
private IToastService toastService = null;
public MyCustomEntityIncrementalCollection(CancellationTokenSource cancelToken, int feedSize = 10)
{
Setup(cancelToken);
this.FeedSize = feedSize;
toastService = IoC.Get<IToastService>();
searchentityService = IoC.Get<ISearchentityService>();
loginService = IoC.Get<ILoginService>();
entityService = IoC.Get<IentityService>();
}
private async Task<IEnumerable<CustomEntity>> Search()
{
try
{
if (IsFirstSearchResult)
{
var result = await searchentityService.SearchAsync(key, loginService.CurrentUser.Id, CancelToken, loginService.CurrentToken.AccessToken, 1, 50);
if (result == null)
{
toastService.ShowAsync("Sin resultados", "No se han encontrado coincidencias");
}
PageNo = result.paging.pageNo;
PageCount = result.paging.pageCount;
PageSize = result.paging.pageSize;
TotalRecordCount = result.paging.totalRecordCount;
IsFirstSearchResult = false;
return result.data;
}
else
{
var result = await searchentityService.SearchAsync(key, loginService.CurrentUser.Id, CancelToken, loginService.CurrentToken.AccessToken, (PageNo + 1), 50);
PageNo = result.paging.pageNo;
PageCount = result.paging.pageCount;
PageSize = result.paging.pageSize;
TotalRecordCount = result.paging.totalRecordCount;
return result.data;
}
}
catch (Exception)
{
}
return null;
}
public async Task TurnOnSearchMode(string keyword)
{
if (string.IsNullOrEmpty(keyword) || string.IsNullOrWhiteSpace(keyword))
throw new Exception(" keyword is invalid");
searchMode = true;
key = keyword;
IsFirstSearchResult = true;
this.ClearItems();
await Task.Delay(500);
await LoadMoreItemsAsync(1);
}
public async Task TurnOffSearchMode()
{
searchMode = false;
IsFirstSearchResult = true;
key = "";
this.ClearItems();
await LoadMoreItemsAsync(1);
}
public override async Task<IEnumerable<CustomEntity>> LoadDataAsync()
{
try
{
if (this.Items.Count == 0)
{
var result = await entityService.MyEntities(CancelToken, loginService.CurrentToken.AccessToken, 1, FeedSize);
if (result != null && result.data != null)
{
PageNo = result.paging.pageNo;
PageCount = result.paging.pageCount;
PageSize = result.paging.pageSize;
TotalRecordCount = result.paging.totalRecordCount;
return result.data;
}
}
else
{
var result = await entityService.MyEntities(CancelToken, loginService.CurrentToken.AccessToken, (PageNo + 1), FeedSize);
PageNo = result.paging.pageNo;
PageCount = result.paging.pageCount;
PageSize = result.paging.pageSize;
TotalRecordCount = result.paging.totalRecordCount;
return result.data;
}
}
catch (Exception)
{
}
return null;
}
public override IAsyncOperation<LoadMoreItemsResult> LoadMoreItemsAsync(uint count)
{
return AsyncInfo.Run(async c =>
{
await Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Low, (() =>
{
IsLoading = true;
}));
if (searchMode == false)
{
try
{
var data = await LoadDataAsync();
if (data != null && data.Any())
{
HasMoreItems = true;
}
else
{
HasMoreItems = false;
}
if (data != null)
{
await Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, (() =>
{
foreach (var item in data)
{
this.Add(item);
}
})).AsTask().ContinueWith(z => { data = null; });
}
}
catch (Exception ex)
{
Debug.WriteLine("Se ha producido un error al buscar videos");
}
}
else
{
try
{
var data = await Search();
if (data != null && data.Any())
{
HasMoreItems = true;
}
else
{
HasMoreItems = false;
}
if (data != null)
{
await Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, (() =>
{
foreach (var item in data)
{
this.Add(item);
}
})).AsTask().ContinueWith(z => { data = null; });
}
}
catch (Exception ex)
{
Debug.WriteLine("Se ha producido un error al buscar videos");
}
}
await Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Low, (() =>
{
IsLoading = false;
}));
return new LoadMoreItemsResult() { Count = count };
});
}
}
最後に、私はちょうど、コンストラクタ、または別の場所で私のビューモデルで初期ロードを呼び出すを作成します。
this.MyEntities = new Infrastructure.Collections.MyCustomEntityAppraisalIncrementalCollection(cancelToken, 20);
await MyEntities.LoadMoreItemsAsync(1);