This question is locked. New answers and comments are not allowed.
After a little research and trial, I figured out that the basics of RadDataPager really just loads everything from a source and page it. Given I use WCF Data Services, I want to lazy load additional pages when needed. As far as I understand, I need to implement IPagedCollectionView to get the functionality I want, as Unbound Mode doesn't cut it. I want to show how many pages are available to the user, and I want to cache already retrived items. Now, I found an example around here which I have adapted, but it still doesn't work properly and as expected. My implementation is as follows:
Note that I have a RadGridView and a RadDataPager. They both correctly bound to this "collection" in Xaml. Basically like this where PagedCollection equals a LazyPagedCollectionView:
There's a few things that don't really work here.
1. Max amount of pages only shows as the amount of pages you have lazily loaded. TotalItemCount are correctly updated and notified via PropertyChanged event, but it doesn't seem like RadDataPager is really listening to this change. I would assume that the mathematics behind the scene that displays this number would be tied to this property, but I may be wrong? If I'm required to know the total amount of items beforehand, it would be in my opinion a serious flaw.
2.When next is clicked in the RadDataPager, the next page of data is correctly loaded into the wrapped collection, and CollectionChanged is called and PropertyChanged is called for "ItemCount" if appropriate, followed by PageChanged event. RadDataGrid however doesn't change the page(!). To get that to work, I have to call CollectionChanged event with NotifyCollectionChangedAction.Reset instead of just forwarding the correct change event of the wrapped collection. Doesn't seems like RadDataGrid has any concept of the PageChanged event. Binding RadGridView to the RadDataPager's PagedSource doesn't help either.
Those are the 2 major issues I can't really wrap my head around right...it just seems illogical to me, but would be nice if someone could either point out errors or confirm any flaws in the control.
public class LazyPagedCollectionWrapper<T> : IPagedCollectionView, INotifyPropertyChanged, INotifyCollectionChanged, IEnumerable<T> where T:new(){ public event EventHandler<EventArgs> PageChanged; public event EventHandler<PageChangingEventArgs> PageChanging; public event PropertyChangedEventHandler PropertyChanged; public event NotifyCollectionChangedEventHandler CollectionChanged; private readonly IRepository<T> repository; private readonly Expression<Func<T, object>>[] eagerProperties; private readonly DataServiceCollection<T> dataServiceCollection; private int nextNewPageIndex; public LazyPagedCollectionWrapper(int pageSize, IRepository<T> repository, params Expression<Func<T, object>>[] eagerProperties) { PageSize = pageSize; this.repository = repository; this.eagerProperties = eagerProperties; this.dataServiceCollection = repository.Result as DataServiceCollection<T>; this.dataServiceCollection.CollectionChanged += OnDataServiceCollectionChanged; this.dataServiceCollection.LoadCompleted += OnDataServiceLoadCompleted; } public bool MoveToFirstPage() { return MoveToPage(0); } public bool MoveToLastPage() { var lastIndex = TotalItemCount / PageSize; return MoveToPage(TotalItemCount % PageSize == 0 ? lastIndex - 1 : lastIndex); } public bool MoveToNextPage() { return MoveToPage(PageIndex + 1); } public bool MoveToPreviousPage() { return MoveToPage(PageIndex - 1); } public bool MoveToPage(int newPageIndex) { if (OnPageChanging(newPageIndex) && newPageIndex > -1 && newPageIndex < TotalItemCount / PageSize) return false; nextNewPageIndex = newPageIndex; if (ItemCount < (newPageIndex + 1) * PageSize) repository.LoadPaged(newPageIndex, PageSize, eagerProperties); else SwitchPage(newPageIndex); return true; } public bool CanChangePage { get { return true; } } private bool isPageChanging; public bool IsPageChanging { get { return isPageChanging; } set { isPageChanging = value; OnPropertyChanged("IsPageChanging"); } } public int ItemCount { get { return dataServiceCollection.Count; } } private int pageIndex; public int PageIndex { get { return pageIndex; } set { pageIndex = value; OnPropertyChanged("PageIndex"); } } private int pageSize; public int PageSize { get { return pageSize; } set { pageSize = value; OnPropertyChanged("PageSize"); } } private int totalItemCount; public int TotalItemCount { get { return totalItemCount; } set { totalItemCount = value; OnPropertyChanged("TotalItemCount"); } } protected virtual void OnPageChanged() { if (PageChanged != null) PageChanged(this, EventArgs.Empty); } protected virtual bool OnPageChanging(int newPageIndex) { var e = new PageChangingEventArgs(newPageIndex); if (PageChanging != null) PageChanging(this, e); return e.Cancel; } protected virtual void OnPropertyChanged(string propertyName) { if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); } protected virtual void OnCollectionChanged(NotifyCollectionChangedEventArgs e) { if (CollectionChanged != null) CollectionChanged(this, e); } private void SwitchPage(int newPageIndex) { IsPageChanging = true; PageIndex = newPageIndex; IsPageChanging = false; OnPageChanged(); } private void OnDataServiceCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) { OnCollectionChanged(e); switch(e.Action) { case NotifyCollectionChangedAction.Add: case NotifyCollectionChangedAction.Remove: case NotifyCollectionChangedAction.Reset: OnPropertyChanged("ItemCount"); break; } } private void OnDataServiceLoadCompleted(object sender, LoadCompletedEventArgs e) { TotalItemCount = (int)e.QueryOperationResponse.TotalCount; SwitchPage(nextNewPageIndex); } public IEnumerator<T> GetEnumerator() { if (ItemCount == 0) return dataServiceCollection.Take(0).GetEnumerator(); if ((PageIndex + 1) * PageSize > TotalItemCount) return dataServiceCollection. Skip(PageIndex * PageSize). Take(((PageIndex + 1) * PageSize) - TotalItemCount). GetEnumerator(); return dataServiceCollection.Skip(PageIndex * PageSize).Take(PageSize).GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); }}Note that I have a RadGridView and a RadDataPager. They both correctly bound to this "collection" in Xaml. Basically like this where PagedCollection equals a LazyPagedCollectionView:
<telerik:RadGridView ItemsSource="{Binding PagedCollection}" /><telerik:RadDataPager Source="{Binding PagedCollection}" />There's a few things that don't really work here.
1. Max amount of pages only shows as the amount of pages you have lazily loaded. TotalItemCount are correctly updated and notified via PropertyChanged event, but it doesn't seem like RadDataPager is really listening to this change. I would assume that the mathematics behind the scene that displays this number would be tied to this property, but I may be wrong? If I'm required to know the total amount of items beforehand, it would be in my opinion a serious flaw.
2.When next is clicked in the RadDataPager, the next page of data is correctly loaded into the wrapped collection, and CollectionChanged is called and PropertyChanged is called for "ItemCount" if appropriate, followed by PageChanged event. RadDataGrid however doesn't change the page(!). To get that to work, I have to call CollectionChanged event with NotifyCollectionChangedAction.Reset instead of just forwarding the correct change event of the wrapped collection. Doesn't seems like RadDataGrid has any concept of the PageChanged event. Binding RadGridView to the RadDataPager's PagedSource doesn't help either.
Those are the 2 major issues I can't really wrap my head around right...it just seems illogical to me, but would be nice if someone could either point out errors or confirm any flaws in the control.