It is clear that a good data driven Windows Phone 7 application must have a smart approach of handling large amounts of data and keeping jagged scrolling and long lasting loading screens away from the end-users. There are a bunch of approaches which handle similar situations but recently I had a discussion with a developer using our controls which focused on implementing data paging as a way of coping with large amounts of data.
During this discussion I came up with an idea to utilize the OnDemandManual data virtualization mode of our RadDataBoundListBox to implement a mechanism which loads pages of data and allows the end user to navigate between pages by providing previous and next buttons at the end of the scrollable list.
The XAML code for this scenario is as simple as that:
<
Grid
x:Name
=
"LayoutRoot"
Background
=
"Transparent"
>
<
Grid.Resources
>
<
DataTemplate
x:Key
=
"DataVirtualizationTemplateNextPrev"
>
<
StackPanel
Orientation
=
"Horizontal"
>
<
Button
x:Name
=
"btnPrev"
Content
=
"back"
Click
=
"btnPrev_Click"
/>
<
Button
x:Name
=
"btnNext"
Content
=
"next"
Click
=
"btnNext_Click"
/>
</
StackPanel
>
</
DataTemplate
>
<
DataTemplate
x:Key
=
"DataVirtualizationTemplateNext"
>
<
StackPanel
Orientation
=
"Horizontal"
>
<
Button
x:Name
=
"btnNext"
Content
=
"next"
Click
=
"btnNext_Click"
/>
</
StackPanel
>
</
DataTemplate
>
<
DataTemplate
x:Key
=
"DataVirtualizationTemplatePrev"
>
<
StackPanel
Orientation
=
"Horizontal"
>
<
Button
x:Name
=
"btnPrev"
Content
=
"back"
Click
=
"btnPrev_Click"
/>
</
StackPanel
>
</
DataTemplate
>
</
Grid.Resources
>
<
telerikPrimitives:RadDataBoundListBox
x:Name
=
"listBox"
DataVirtualizationMode
=
"OnDemandManual"
>
<
telerikPrimitives:RadDataBoundListBox.ItemTemplate
>
<
DataTemplate
>
<
Border
Background
=
"ForestGreen"
MinHeight
=
"150"
>
<
TextBlock
Text
=
"{Binding}"
/>
</
Border
>
</
DataTemplate
>
</
telerikPrimitives:RadDataBoundListBox.ItemTemplate
>
</
telerikPrimitives:RadDataBoundListBox
>
</
Grid
>
As you can see, I have a RadDataBoundListBox control which has its DataVirtualizationMode property set to OnDemandManual and defines a simple data template for its items. In the resources dictionary of my layout root I have defined three additional data templates which I am going to use to display the navigation buttons discussed above. You may ask why three templates instead of one? The answer is simple: I do not want to display a previous button when I am at the first page, and do not want to display a next button when I am at the last page. Also, I want to display both buttons when I am somewhere in between.I am also going to access these templates in code and switch between them as the end user navigates trough pages.
The code-behind file of this example is also straightforward. The following snippet shows the method that loads the data according to the current page and decides which DataVirtualizationItemTemplate which will be used according to the current page. The DataVirtualizationItemTemplate defines the appearance of the specialized data virtualization item which will be displayed at the end of the scrollable list and which, when tapped, fires the DataRequested event which can be used to load further data items:
private
void
LoadPage(
int
page)
{
List<
string
> source =
new
List<
string
>();
int
endIndex = page +
this
.pageSize;
for
(
int
i = page; i < endIndex; i++)
{
source.Add(
this
.dataSource[i]);
}
if
(endIndex == 200)
{
this
.listBox.DataVirtualizationItemTemplate =
this
.LayoutRoot.Resources[
"DataVirtualizationTemplatePrev"
]
as
DataTemplate;
}
else
if
(
this
.pageStartIndex == 0)
{
this
.listBox.DataVirtualizationItemTemplate =
this
.LayoutRoot.Resources[
"DataVirtualizationTemplateNext"
]
as
DataTemplate;
}
else
{
this
.listBox.DataVirtualizationItemTemplate =
this
.LayoutRoot.Resources[
"DataVirtualizationTemplateNextPrev"
]
as
DataTemplate;
}
this
.listBox.ItemsSource = source;
}
The page argument of this method is actually the page index which I will be loading. I also have a pageSize field which defines how many items will be loaded at a time. The dataSource is a collection of data items which is used to load the paged data. In the real-life scenario this would be a web service that allows for requesting items from a given index and with a given count (ODATA for instance).
Here is what happens when the user taps on a navigation button:
private
void
btnPrev_Click(
object
sender, RoutedEventArgs e)
{
this
.pageStartIndex -=
this
.pageSize;
this
.LoadPage(
this
.pageStartIndex);
}
private
void
btnNext_Click(
object
sender, RoutedEventArgs e)
{
this
.pageStartIndex +=
this
.pageSize;
this
.LoadPage(
this
.pageStartIndex);
}
Here is how this looks like on the WP7 emulator:
Some more information about the new Data Virtualization modes of the RadDataBoundListBox can be found here:
and here:
You can find attached the whole WP7 app that implements this scenario and play with it to further explore the specifics of this approach.