First of all, I have read the blog posts (http://blogs.telerik.com/rossenhristov/posts/10-03-10/q1_2010_new_feature_paging_with_radgridview_for_silverlight_and_wpf.aspx) and I am not using RIA services.
Second, I have a working paged implementation using QueryableCollectionView to wrap my ObservableCollection. The problem is that I know how big the total dataset is, but I'm not allowed to set TotalItemCount. I want to return 500 objects at a time from a WCF service, so as the user pages, I would like to fill in 500 new objects - BUT I want the pager to say I am on "Page 1 of 200" or "Items 1-100 of 1000" and when I get to the end of the 500 objects, go get the next 500 (I.e., the IPagedCollectionView interface.) If I update the collection in the Paging event handlers, then the "of x" part goes up, as expected, but unless you page "off the end" it gives the illusion there are only 500 objects.
From searching, the solution seems to be that I must implement the IPagedCollectionView interface myself.
Does anyone have a recommended approach or complete example? Should I extend ObservableCollection and implement IPagedCollectionView there, for example?
I studied the section from the post above
And it would seem that if both my RadDataPager.Source and RadGridView.ItemsSource are bound to a QueryableCollectionView, it should work, but it doesn't - I need to point the RadDataPager's source at the ElementName=RadGridView, Path=Items for it to work.
In short, think of it as a lazy-load, x objects at a time out of a known total of y objects, where the IPagedCollectionView members notice the holes and fetch the data on-demand.
Thanks,
Tim
Second, I have a working paged implementation using QueryableCollectionView to wrap my ObservableCollection. The problem is that I know how big the total dataset is, but I'm not allowed to set TotalItemCount. I want to return 500 objects at a time from a WCF service, so as the user pages, I would like to fill in 500 new objects - BUT I want the pager to say I am on "Page 1 of 200" or "Items 1-100 of 1000" and when I get to the end of the 500 objects, go get the next 500 (I.e., the IPagedCollectionView interface.) If I update the collection in the Paging event handlers, then the "of x" part goes up, as expected, but unless you page "off the end" it gives the illusion there are only 500 objects.
From searching, the solution seems to be that I must implement the IPagedCollectionView interface myself.
Does anyone have a recommended approach or complete example? Should I extend ObservableCollection and implement IPagedCollectionView there, for example?
I studied the section from the post above
IV. Paging collections implementing IPagedCollectionView
And it would seem that if both my RadDataPager.Source and RadGridView.ItemsSource are bound to a QueryableCollectionView, it should work, but it doesn't - I need to point the RadDataPager's source at the ElementName=RadGridView, Path=Items for it to work.
In short, think of it as a lazy-load, x objects at a time out of a known total of y objects, where the IPagedCollectionView members notice the holes and fetch the data on-demand.
Thanks,
Tim
10 Answers, 1 is accepted
0
Hello Tim,
I have good news for you. Due to similar requests we have developed a new feature of RadDataPager called Unbound Mode. Basically, you do not set any Source for the pager, i.e.e you do not need to implement the IPagedCollectionView interface. Instead you can set the ItemCount property manually. Once you set the ItemCount and PageSize the pager does the math and know the number of pages.
You can think of the Unbound Mode as of using the pager solely for its UI. Nothing more. When the user goes to a page, the PageIndexChanged event will be raised. By attaching to this event, in the event handler you will get the page index that user has requested. Knowing this page index, you can call any kind of service and return the appropriate data to the client.
This approach is way more easier than implementing the whole IPagedCollectionView interface.
You will need to upgrade to the Service Pack version coming out tomorrow in order to have this feature.
I hope this helps.
Best wishes,
Ross
the Telerik team
I have good news for you. Due to similar requests we have developed a new feature of RadDataPager called Unbound Mode. Basically, you do not set any Source for the pager, i.e.e you do not need to implement the IPagedCollectionView interface. Instead you can set the ItemCount property manually. Once you set the ItemCount and PageSize the pager does the math and know the number of pages.
You can think of the Unbound Mode as of using the pager solely for its UI. Nothing more. When the user goes to a page, the PageIndexChanged event will be raised. By attaching to this event, in the event handler you will get the page index that user has requested. Knowing this page index, you can call any kind of service and return the appropriate data to the client.
This approach is way more easier than implementing the whole IPagedCollectionView interface.
You will need to upgrade to the Service Pack version coming out tomorrow in order to have this feature.
I hope this helps.
Best wishes,
Ross
the Telerik team
Do you want to have your say when we set our development plans?
Do you want to know when a feature you care about is added or when a bug fixed?
Explore the
Telerik Public Issue Tracking
system and vote to affect the priority of the items
0
Tim
Top achievements
Rank 1
answered on 22 Sep 2010, 01:52 PM
That's good news, thanks. I can't upgrade just yet unfortunately. I modified your EndlessPagedCollectionView example to suit my needs for now. I've included it for reference. I called it BoundedPagedCollectionView since it knows the upper bound in advance, but pages in chunks on-demand. The WCF service call is simulated with a DispatchTimer and completed asynchronously when the timer fires.
Tim
Tim
using
System;
using
System.Collections.Generic;
using
System.Collections;
using
System.Windows.Threading;
using
Telerik.Windows.Controls;
using
System.ComponentModel;
using
System.Collections.Specialized;
namespace
SilverlightApplication1
{
/// <summary>
///
/// </summary>
public
class
BoundedPagedCollectionView : 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;
private
int
MaxOrders;
private
RadGridView GridView;
private
readonly
List<Order> Orders =
new
List<Order>();
public
BoundedPagedCollectionView(
int
maxOrders, RadGridView gridView)
{
MaxOrders = maxOrders;
GridView = gridView;
PageChanging += Bounded
PagedCollection_PageChanging;
}
bool
IPagedCollectionView.CanChangePage
{
get
{
return
true
; }
}
bool
IPagedCollectionView.IsPageChanging
{
get
{
return
this
.isPageChanging; }
}
private
void
SetIsPageChanging(
bool
value)
{
if
(
this
.isPageChanging != value)
{
this
.isPageChanging = value;
this
.OnPropertyChanged(
"IsPageChanging"
);
}
}
int
IPagedCollectionView.ItemCount
{
get
{
return
MaxOrders;
}
}
bool
IPagedCollectionView.MoveToFirstPage()
{
return
((IPagedCollectionView)
this
).MoveToPage(0);
}
bool
IPagedCollectionView.MoveToLastPage()
{
return
((IPagedCollectionView)
this
).MoveToPage(((IPagedCollectionView)
this
).TotalItemCount / ((IPagedCollectionView)
this
).PageSize);
}
bool
IPagedCollectionView.MoveToNextPage()
{
return
((IPagedCollectionView)
this
).MoveToPage(((IPagedCollectionView)
this
).PageIndex + 1);
}
private
int
__pageIndex;
bool
IPagedCollectionView.MoveToPage(
int
pageIndex)
{
if
(
this
.OnPageChanging(pageIndex) && pageIndex != -1)
{
return
false
;
}
__pageIndex = pageIndex;
if
(Orders.Count < (__pageIndex + 1) * ((IPagedCollectionView)
this
).PageSize)
{
//
// This simulates a WCF callback in that the update comes in on a different thread
// at some later point - 500 milliseconds.
//
DispatcherTimer pageTimer =
new
DispatcherTimer {Interval =
new
TimeSpan(0, 0, 0, 0, 500)};
pageTimer.Tick += CompletionCallback;
pageTimer.Start();
GridView.IsBusy =
true
;
}
else
{
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
;
}
private
void
CompletionCallback(
object
sender, EventArgs e)
{
(sender
as
DispatcherTimer).Stop();
if
(Orders.Count < (__pageIndex + 1) * ((IPagedCollectionView)
this
).PageSize)
{
for
(
int
i = Orders.Count; i < (__pageIndex + 1) * ((IPagedCollectionView)
this
).PageSize && i < MaxOrders; i++)
{
Orders.Add(
new
Order(i));
}
}
GridView.IsBusy =
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();
}
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();
}
}
}
int
IPagedCollectionView.TotalItemCount
{
get
{
return
MaxOrders;
}
}
public
System.Collections.IEnumerator GetEnumerator()
{
// No orders, return empty Enumerator
if
(Orders.Count == 0)
{
return
Orders.GetRange(0, 0).GetEnumerator();
}
// Not a full last page? Return partial Enumerator
if
(((IPagedCollectionView)
this
).PageIndex * ((IPagedCollectionView)
this
).PageSize + pageSize > Orders.Count)
{
return
Orders.GetRange(((IPagedCollectionView)
this
).PageIndex*((IPagedCollectionView)
this
).PageSize,
Orders.Count -
((IPagedCollectionView)
this
).PageIndex*((IPagedCollectionView)
this
).PageSize).
GetEnumerator();
}
// Return a full page
return
Orders.GetRange(((IPagedCollectionView)
this
).PageIndex*((IPagedCollectionView)
this
).PageSize,
((IPagedCollectionView)
this
).PageSize).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);
}
}
private
void
Bounded
PagedCollection_PageChanging(
object
sender, PageChangingEventArgs e)
{
if
(e.NewPageIndex > MaxOrders / pageSize)
{
e.Cancel =
true
;
}
}
/// <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
;
}
}
}
}
}
0
Hello Tim,
This is fantastic!
Thank you for sharing the code with the community.
You can contribute even more if you create a sample runnig project which demonstrates your accomplishment and upload it to our code-libraries.
As a small benefit you can get up to 10 000 Telerik Points.
Thank you in advance!
All the best,
Veselin Vasilev
the Telerik team
This is fantastic!
Thank you for sharing the code with the community.
You can contribute even more if you create a sample runnig project which demonstrates your accomplishment and upload it to our code-libraries.
As a small benefit you can get up to 10 000 Telerik Points.
Thank you in advance!
All the best,
Veselin Vasilev
the Telerik team
Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items
0
Tim
Top achievements
Rank 1
answered on 22 Sep 2010, 05:29 PM
Done. I presume it must be approved before it appears because it does not seem to be there at the moment.
Tim
Tim
0
Accepted
Hi Tim,
I have modified it a bit (adding Trial Telerik assemblies and updating the references) and it is already live at
http://www.telerik.com/community/code-library/silverlight/gridview/a-paged-on-demand-ipagedcollectionview-example-where-chunks-of-a-known-total-are-loaded-as-requested.aspx
I have updated your Telerik points.
Thank you once again for your efforts.
Kind regards,
Veselin Vasilev
the Telerik team
I have modified it a bit (adding Trial Telerik assemblies and updating the references) and it is already live at
http://www.telerik.com/community/code-library/silverlight/gridview/a-paged-on-demand-ipagedcollectionview-example-where-chunks-of-a-known-total-are-loaded-as-requested.aspx
I have updated your Telerik points.
Thank you once again for your efforts.
Kind regards,
Veselin Vasilev
the Telerik team
Do you want to have your say when we set our development plans?
Do you want to know when a feature you care about is added or when a bug fixed?
Explore the
Telerik Public Issue Tracking
system and vote to affect the priority of the items
0
Tim
Top achievements
Rank 1
answered on 24 Sep 2010, 03:41 PM
Cool, I am glad to help. You have a fine product suite and an excellent relationship with the community.
Tim
Tim
0
Tim
Top achievements
Rank 1
answered on 28 Sep 2010, 03:58 PM
Suppose I wanted to augment the RadDataPager (see attached image) so that included the # of items loaded out of a known total, a page size control, and a button which would export to CSV. Is there a sample out there on modifying or extending the control template? I'd like to include the extra bits INSIDE the RadDataPager itself.
Thanks,
Tim
Thanks,
Tim
0
Hello,
Vlad
the Telerik team
Yes, you can restyle the pager completely with Blend since the control is completely lookless. You can check this blog post for more info.
Kind regards,Vlad
the Telerik team
Do you want to have your say when we set our development plans?
Do you want to know when a feature you care about is added or when a bug fixed?
Explore the
Telerik Public Issue Tracking
system and vote to affect the priority of the items
0
Hello!
Sorry to bring up this old topic again, but i have the same issue.
I implement the indicated approach supplied by Ross using the DataPager in it's unbound mode. Everything is working as i expect but now i lost the Filter abilities. Example: If I'm in the Page 1, only people with "A" name appears, and if the user try to use the RadGridView Filter and choose to show people with Name with "B" nothing will show of course because the GridView does not have the collection yet.
Is there a way to workaround this? I mean implement a way when the user use the filter i call me service and return a new collection to the GridView?
Thanks a lot!
Sorry to bring up this old topic again, but i have the same issue.
I implement the indicated approach supplied by Ross using the DataPager in it's unbound mode. Everything is working as i expect but now i lost the Filter abilities. Example: If I'm in the Page 1, only people with "A" name appears, and if the user try to use the RadGridView Filter and choose to show people with Name with "B" nothing will show of course because the GridView does not have the collection yet.
Is there a way to workaround this? I mean implement a way when the user use the filter i call me service and return a new collection to the GridView?
Thanks a lot!
0
Hi Joao Paulo Grassi,
Ross
the Telerik team
You can bind RadGridView and RadDataPager to one of our data source controls. In this way you will have both filtering and paging on the server.
We have:
- RadDomainDataSource for WCF RIA Services.
- RadDataServiceDataSource for WCF Data Services.
Please, explore their online demos. They show the integration between the three controls.
Ross
the Telerik team
Explore the entire Telerik portfolio by downloading the Ultimate Collection trial package. Get it now >>