/// <summary> /// Launch the loading of a data page. /// If a task is currently running, it gets discarded (callbacks won't be called). /// If the first page loading is asked whereas one or several pages have already been loaded, a "refresh" is detected. /// </summary> /// <param name="pageNumber">The page number to load (pageNumber = 1 for the first page).</param> /// <param name="calledFromScroll">True if LoadPage has been called from OnScroll method of the IInfiniteListLoader.</param> public Task <PageResult <TResult> > LoadPage(int pageNumber, bool calledFromScroll = false) { Contract.Requires(() => pageNumber > 0); Contract.Requires( () => calledFromScroll || (pageNumber == 1 || pageNumber == (PageLoadedCount + 1)), "The paginator can only load sequential pages"); InternalLogger.Info($"Requesting page n°{pageNumber} load, {PageLoadedCount} pages loaded so far"); lock (_syncRoot) { if (calledFromScroll) { if (pageNumber <= PageLoadedCount) { InternalLogger.Info($"Aborting IInfiniteListLoader call: only a direct call to LoadPage can lead to a refresh"); return(Task.FromResult(PageResult <TResult> .Empty)); } } if (pageNumber > PageLoadedCount && IsFull) { InternalLogger.Info($"Cannot load page {pageNumber} total item count has already been reached ({TotalCount})"); return(Task.FromResult(PageResult <TResult> .Empty)); } if (pageNumber == 1 && PageLoadedCount > 0) { InternalLogger.Info("Refresh detected"); _refreshRequested = true; } else { _refreshRequested = false; } if (LoadingTask != null && LoadingTask.IsNotCompleted) { // Cancels callbacks of previous task if not completed LoadingTask.CancelCallbacks(); } LoadingTask = new TaskMonitor <PageResult <TResult> > .Builder( () => _pageSourceLoader(pageNumber, PageSize, _refreshRequested)) .WithWhenSuccessfullyCompleted(OnPageRetrieved) .WithWhenCompleted(OnTaskCompleted) .Build(); InternalLogger.Info($"Page n°{pageNumber} loading started"); LoadingTask.Start(); return(LoadingTask.Task); } }