This is a migrated thread and some comments may be shown as answers.

Using IPagedCollectionView

2 Answers 257 Views
GridView
This is a migrated thread and some comments may be shown as answers.
Wesley Witt
Top achievements
Rank 1
Wesley Witt asked on 16 Dec 2010, 06:46 PM
I have an implementation of IPagedCollectionView that I'm using for custom paging of SQL data.  Things seem to be working almost perfectly, but I have one issue that I need help with.

When I change pages in the RadDataPager my IPagedCollectionView is called appropriately, MoveToNextPage() is called.  My code responds by retrieving the next page of data and changing the current page index value.  The problem is that the RadGridView does not update its display with the result being that the new page of data is not displayed in the control.  In debugging this I can see that the control is not calling GetEnumerator() after the page change.  My suspicion is that the grid control is assuming that the enumerator will not change, just the contents of the collection will change.  In my case I am changing the collection on each page change an expecting the grid control to perform a new enumeration by first calling GetEnumerator().

Comments?

*** Actually, changing the code to use the same collection for the enumeration does not improve things.  Another data point is that the data pager does not update its display to indicate that a page change has happened.  The data pager control always says that it is on page #1.

2 Answers, 1 is accepted

Sort by
0
Rossen Hristov
Telerik team
answered on 17 Dec 2010, 02:36 PM
Hi Wesley Witt,

Are you raising the following events when the page changes:

- CollectionChanged with action Reset: this should make the grid re-enumerate the collection.
- PropertyChanged with property name PageIndex: this should make the pager update its stuff.

By the way, I will post the source code of a dummy implementation of IPagedCollectionView from our example called "Endless Paging". This implementation can help you see what events should be called:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using Telerik.Windows.Data;
using System.ComponentModel;
using System.Collections.Specialized;
using System.Windows.Data;
using System.Globalization;
 
namespace Telerik.Windows.Examples.GridView
{
    /// <summary>
    /// Endless paged collection view for testing purposes.
    /// </summary>
    public class EndlessPagedCollectionView : IEnumerable
        , IPagedCollectionView
        , INotifyPropertyChanged
        , INotifyCollectionChanged
    {
        public event EventHandler<EventArgs> PageChanged;
        public event EventHandler<PageChangingEventArgs> PageChanging;
        public event PropertyChangedEventHandler PropertyChanged;
        public event NotifyCollectionChangedEventHandler CollectionChanged;
 
        private int pageIndex = -1;
        private bool isPageChanging;
        private int pageSize;
 
        /// <summary>
        /// We always can. We are endless.
        /// </summary>
        bool IPagedCollectionView.CanChangePage
        {
            get { return true; }
        }
 
        bool IPagedCollectionView.IsPageChanging
        {
            get { return this.isPageChanging; }
        }
 
        /// <summary>
        /// Visual Basic is so lame!
        /// </summary>
        private void SetIsPageChanging(bool value)
        {
            if (this.isPageChanging != value)
            {
                this.isPageChanging = value;
                this.OnPropertyChanged("IsPageChanging");
            }
        }
 
        /// <summary>
        /// Since we are endless, the item count is
        /// the amount of items currently known to exist.
        /// In other words the item count is whatever we
        /// have reached.
        /// </summary>
        int IPagedCollectionView.ItemCount
        {
            get
            {
                return (((IPagedCollectionView)this).PageIndex + 1) * ((IPagedCollectionView)this).PageSize;
            }
        }
 
        bool IPagedCollectionView.MoveToFirstPage()
        {
            return ((IPagedCollectionView)this).MoveToPage(0);
        }
 
        bool IPagedCollectionView.MoveToLastPage()
        {
            //We cannot move to the last page since we are endless :)
            return false;
        }
 
        bool IPagedCollectionView.MoveToNextPage()
        {
            return ((IPagedCollectionView)this).MoveToPage(((IPagedCollectionView)this).PageIndex + 1);
        }
 
        bool IPagedCollectionView.MoveToPage(int pageIndex)
        {
            if (this.OnPageChanging(pageIndex) && pageIndex != -1)
            {
                return false;
            }
 
            this.SetIsPageChanging(true);
            this.pageIndex = pageIndex;
            this.SetIsPageChanging(false);
 
            this.OnPropertyChanged("PageIndex");
            this.OnPropertyChanged("ItemCount");
            this.OnPageChanged();
 
            // Call this to inform all listeners that data has changed.
            this.OnCollectionChanged();
 
            return true;
        }
 
        bool IPagedCollectionView.MoveToPreviousPage()
        {
            return ((IPagedCollectionView)this).MoveToPage(((IPagedCollectionView)this).PageIndex - 1);
        }
 
        int IPagedCollectionView.PageIndex
        {
            get { return this.pageIndex; }
        }
 
        int IPagedCollectionView.PageSize
        {
            get
            {
                return this.pageSize;
            }
            set
            {
                if (value < 1)
                {
                    throw new ArgumentOutOfRangeException("value", "The PageSize of an endless collection should be positive.");
                }
 
                if (this.pageSize != value)
                {
                    this.pageSize = value;
                    this.OnPropertyChanged("PageSize");
                    this.OnPropertyChanged("ItemCount");
 
                    // Behave like good collections do.
                    ((IPagedCollectionView)this).MoveToFirstPage();
                }
            }
        }
 
        /// <summary>
        /// We don't know this. Remember we are endless.
        /// </summary>
        int IPagedCollectionView.TotalItemCount
        {
            get { return -1; }
        }
 
        public System.Collections.IEnumerator GetEnumerator()
        {
            // The best part -- true endlessness ;)
            // Now this might crash if we overflow Int32, but in a
            // real scenario new "items" will be returned forever.
            IEnumerable<Order> items = from id in Enumerable.Range(((IPagedCollectionView)this).PageIndex * ((IPagedCollectionView)this).PageSize, ((IPagedCollectionView)this).PageSize)
                                       select new Order(id);
            return items.GetEnumerator();
        }
 
        private void OnPropertyChanged(string propertyName)
        {
            PropertyChangedEventArgs e = new PropertyChangedEventArgs(propertyName);
            if (this.PropertyChanged != null)
            {
                this.PropertyChanged(this, e);
            }
        }
 
        private bool OnPageChanging(int newPageIndex)
        {
            PageChangingEventArgs e = new PageChangingEventArgs(newPageIndex);
            if (this.PageChanging != null)
            {
                this.PageChanging(this, e);
            }
 
            return e.Cancel;
        }
 
        private void OnPageChanged()
        {
            EventArgs e = EventArgs.Empty;
            if (this.PageChanged != null)
            {
                this.PageChanged(this, e);
            }
        }
 
        private void OnCollectionChanged()
        {
            NotifyCollectionChangedEventArgs e = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset);
            if (this.CollectionChanged != null)
            {
                this.CollectionChanged(this, e);
            }
        }
 
        /// <summary>
        /// Sample Order
        /// </summary>
        public class Order
        {
            private int id;
            private DateTime date;
            private double amount;
            private bool confirmed;
            private string code;
            private string country;
 
            /// <summary>
            /// Gets the ID.
            /// </summary>
            /// <value>The ID.</value>
            public int ID
            {
                get { return this.id; }
            }
 
            /// <summary>
            /// Gets or sets the date.
            /// </summary>
            /// <value>The date.</value>
            public DateTime Date
            {
                get
                {
                    return this.date;
                }
                private set
                {
                    this.date = value;
                }
            }
 
            /// <summary>
            /// Gets or sets the amount.
            /// </summary>
            /// <value>The amount.</value>
            public double Amount
            {
                get
                {
                    return this.amount;
                }
                private set
                {
                    this.amount = value;
                }
            }
 
            /// <summary>
            /// Gets or sets a value indicating whether this <see cref="Order"/> is confirmed.
            /// </summary>
            /// <value><c>true</c> if confirmed; otherwise, <c>false</c>.</value>
            public bool Confirmed
            {
                get
                {
                    return this.confirmed;
                }
                private set
                {
                    this.confirmed = value;
                }
            }
 
            /// <summary>
            /// Gets or sets the code.
            /// </summary>
            /// <value>The code.</value>
            public string Code
            {
                get
                {
                    return this.code;
                }
                private set
                {
                    this.code = value;
                }
            }
 
            /// <summary>
            /// Gets or sets the country.
            /// </summary>
            /// <value>The country.</value>
            public string Country
            {
                get
                {
                    return this.country;
                }
                private set
                {
                    this.country = value;
                }
            }
 
            /// <summary>
            /// Initializes a new instance of the <see cref="Order"/> class.
            /// </summary>
            /// <param name="id">The id.</param>
            public Order(int id)
            {
                this.id = id;
                int random = new Random(id).Next(-100, 100);
                this.Date = DateTime.Now.AddDays(random);
                this.Amount = Math.Abs(random);
                this.Confirmed = random % 2 == 0;
 
                int someRandom = Math.Abs(this.id.GetHashCode()) / 10
                    + Math.Abs(this.Date.GetHashCode()) / 10
                    + Math.Abs(this.Amount.GetHashCode()) / 10
                    + Math.Abs(this.Confirmed.GetHashCode()) / 10;
                this.Code = someRandom.ToString() + someRandom.ToString();
 
                switch (random % 5)
                {
                    case 0:
                        this.Country = "USA";
                        break;
                    case 1:
                        this.Country = "UK";
                        break;
                    case 2:
                        this.Country = "Germany";
                        break;
                    case 3:
                        this.Country = "Spain";
                        break;
                    case 4:
                        this.Country = "France";
                        break;
                    default:
                        this.Country = "Other";
                        break;
                }
            }
        }
    }
}

Your other source of info can be the Silverlight class (I know its not WPF but this does not matter -- it's absolutely the same) PagedCollectionView. PagedCollectionView is Microsoft's default implementation of the IPagedCollectionView interface and does everything correctly. You can check its source code with Reflector.

Here is another blog that discusses what needs to be done to implement the interface correctly.

Finally, if you have our source code available, you can dig into Telerik.Windows.Data.QueryableCollection view which also implements Telerik.Windows.Data.IPagedCollectionView (there is no built-in IPagedCollection view in WPF and that is why we have created our own that is absolutely the same as the one found in SL).

Since we share our code-base between Silverlight and WPF, if you implement Telerik.Windows.Data.IPagedCollectionView like in the SL examples above, RadDataPager will work correctly.

I hope this helps. Let me know if there are problems.

Regards,
Ross
the Telerik team
Browse the videos here>> to help you get started with RadControls for WPF
0
Wesley Witt
Top achievements
Rank 1
answered on 17 Dec 2010, 05:21 PM
Thanks a lot for the detailed post.  Prior to your post I did dig into your implementation of QueryableCollection  and saw exactly what you describe here.  Using that information I was able to make it work.  It does seem strange that the grid view requires a CollectionChanged with action Reset.  This seems strange because the collection really hasn't been reset, just the view onto the virtual collection has changed.  I just feels like a weird way for this to work, but thanks for your help.
Tags
GridView
Asked by
Wesley Witt
Top achievements
Rank 1
Answers by
Rossen Hristov
Telerik team
Wesley Witt
Top achievements
Rank 1
Share this question
or