Telerik blogs

Following the great series about RadDataPager started by Rossen and Pavel today I’m going to show you how to implement logical paging. We are going to implement alphabetical paging similar to this ASP.NET AJAX Grid Demo.

As you may already know the key to the heart of the RadDataPager is the IPagedCollectionView interface. You can create your own implementations of this interface and implement any custom logic for paging you want. This is exactly what we are going to do in this article.

Introducing PagedCollectionViewBase and LogicallyPagedCollectionView<T>

If you have looked at IPagedCollectionView interface you may have found out that it is not a trivial interface to implement. It has 5 methods, 6 properties and 2 events – total number of members to implement 13. To ease any further implementation of the paging interface we are going to create a base class that will have most of the members implemented. Meet PagedCollectionViewBase class.

PagedCollectionViewBase class

This is an abstract base class, which implements IEnumerable, INotifyPropertyChanged, INotifyCollectionChanged and of course IPagedCollectionView. It boils down the implementation of the paging to overriding of two members – a property and a method: ItemCount and GetEnumerator(). It also has almost all of its members virtual so you can tweak the default implementation if you like. For the details of the implementation you can look at the attached source code.

Using this base class you can create any kind of derivatives that implement the paging using their own mechanism. One could envision an event based one, which has a custom event raised when the paging needs to happen and providing the current paged items in the events arguments. Another way of implementing the paging is via a filtering predicate.

LogicallyPagedCollectionView<T> class

This class derives from PagedCollectionViewBase and introduces the concept of paging via a predicate. You construct this view passing your collection in the constructor. Then you have to set its PageCount property to the desired number of pages and also you have to set the PagingPredicate property. Let’s look at the predicate property. It is defined like this:

public Expression<Func<T, bool>> PagingPredicate { get; set; }

If you look closely you will see that its type is a LINQ Lambda Expression. This allow us to push the paging operation on the server if the view is initialized with an IQueryable implementation. Here is the code that does the paging itself:

private IQueryable<T> PagedView

{

    get

    {

        var query = this.sourceQueryable;

        if (this.PagingPredicate != null)

        {

            query = query.Where(this.PagingPredicate);

        }

        return query;

    }

}

Implementing alphabetical paging with LogicallyPagedCollectionView<T>

Having LogicallyPagedCollectionView<T> in place implementing alphabetical paging will take no more than a few lines of code. Here is the code-behind for our page:

public MainPage()

{

    this.InitializeComponent();

 

    var pagedCollectionView = new LogicallyPagedCollectionView<Item>(new SampleDataSource().Collection);

    pagedCollectionView.PageCount = 26;

    pagedCollectionView.PagingPredicate =

        (i) => i.Property1.ToLower().StartsWith(PageIndexToCharConverter.Convert(pagedCollectionView.PageIndex).ToString());

 

    this.DataContext = pagedCollectionView;

}

You can see that we are initializing the view with some sample data that Blend generated for us. We are setting the page count to 26 – the number of letters in the English alphabet. Then we are setting the paging predicate which will filter out those items which name doesn’t not start with the given page index converted to a char. Finally we are assigning the view as data context so we can bind to it in the XAML. Before looking at the XAML lets first take a look at the PageIndexToCharConverter class. Here it goes:

public class PageIndexToCharConverter : IValueConverter

{

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)

    {

        int pageNumber = System.Convert.ToInt32(value);

 

        return Convert(pageNumber - 1);

    }

 

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)

    {

        throw new NotImplementedException();

    }

 

    public static char Convert(int pageIndex)

    {

        return (char)(pageIndex + 'a');

    }

}

It is a simple value converter class which converts given page index to the appropriate letter in the alphabet. The trick here is that we are going to use the same class to convert the pager buttons’ content to alphabet so we have to be careful when to use the page number or the page index.

Now lets take a look at the XAML for our sample:

<Grid x:Name="LayoutRoot">

    <Grid.RowDefinitions>

        <RowDefinition />

        <RowDefinition Height="Auto" />

    </Grid.RowDefinitions>

    <telerik:RadGridView ItemsSource="{Binding}" AutoGenerateColumns="False" ShowGroupPanel="False">

        <telerik:RadGridView.Columns>

            <telerik:GridViewDataColumn Header="ID" DataMemberBinding="{Binding Property2}" />

            <telerik:GridViewDataColumn Header="Name" DataMemberBinding="{Binding Property1}" />

            <telerik:GridViewDataColumn Header="Company Name" DataMemberBinding="{Binding Property3}" />

            <telerik:GridViewDataColumn Header="Email" DataMemberBinding="{Binding Property4}" />

            <telerik:GridViewDataColumn Header="Phone" DataMemberBinding="{Binding Property5}" />

        </telerik:RadGridView.Columns>

    </telerik:RadGridView>

    <telerik:RadDataPager Grid.Row="1"

       Source="{Binding}"

       NumericButtonCount="{Binding PageCount}"

       DisplayMode="Numeric"

       NumericButtonStyle="{StaticResource PagerToggleButtonStyle}"

   />

</Grid>

RadGridView and RadDataPager are both bound to the paged collection view. Pager’s NumericButtonCount is also bound to the PageCount property of the view. The last piece of the puzzle is the custom style for the pager’s buttons:

<local:PageIndexToCharConverter x:Key="PageIndexToCharConverter"/>

 

<Style x:Key="PagerToggleButtonStyle" TargetType="ToggleButton">

    <Setter Property="ContentTemplate">

        <Setter.Value>

            <DataTemplate>

                <TextBlock Text="{Binding Converter={StaticResource PageIndexToCharConverter}}"    />

            </DataTemplate>

        </Setter.Value>

    </Setter>

    <Setter Property="MinWidth" Value="25" />

    <Setter Property="Margin" Value="1,0" />

</Style>

You can see that how the custom value converter is used to format the content of the buttons.

As always you can play with the application right here in the blog post:

You can find the source code here.

(In the WPF version there is another page that illustrates how the paging takes place on the SQL Server. You will need Northwind database installed in your local SQLEXPRESS instance)

Have a great and successful rad paging (or is it just paging? :)


About the Author

Stefan Dobrev

 is Team Lead in Black Dragon Team

Related Posts

Comments

Comments are disabled in preview mode.