Silverlight DataGrid – A Simple Pager Control

by Dean 11. February 2009 10:39

I love the fact that in Silverlight you can get all of your data onto the datagrid at the same time, rather than having to used a paged control in ASP.NET. However I’ve found that some users really want the data paging to remain, which means that I’ve got to roll may own DataGrid paging control.

I know there are a few example out there, but I wanted to create a control that was a simple as possible but covered all of the major bases – so as little ‘code-behind’ as possible, and all the styling done in Blend.

So this is what I came up with:

Screenshot

 

pagergrid

 

Here’s the XAML

 

<Grid x:Name="LayoutRoot" Background="White" Width="Auto" 
      Height="Auto" HorizontalAlignment="Left" VerticalAlignment="Top" 
      Margin="10,10,10,10">
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="*"/>
        <RowDefinition Height="Auto"/>
    </Grid.RowDefinitions>
    <StackPanel Orientation="Horizontal" HorizontalAlignment="Left" 
                    VerticalAlignment="Top">
        <TextBlock Text="Page 1 of 10 (Total 100 items)" x:Name="Total" 
                    HorizontalAlignment="Center" VerticalAlignment="Center"/>
        <TextBlock Text="Page Size" Margin="10,0,0,0" 
                    HorizontalAlignment="Center" VerticalAlignment="Center"/>
        <ComboBox Name="PageSize" SelectionChanged="PageSizeChanged" 
                    Margin="3,3,3,3" HorizontalAlignment="Center" 
                    VerticalAlignment="Center" />
    </StackPanel>
    <data:DataGrid HorizontalAlignment="Stretch" VerticalAlignment="Stretch" 
                    DataContext="{Binding Mode=OneWay, 
                        Source={StaticResource PersonCollectionDS}}" 
                    ItemsSource="{Binding}" x:Name="MainGrid" 
                    CanUserSortColumns="False" Grid.Row="1" />
    <Border Margin="0,3,0,3" Padding="5,5,5,5" BorderBrush="Gray" 
                    BorderThickness="1,1,1,1" Grid.Row="2">
        <StackPanel Height="Auto" HorizontalAlignment="Center" 
                    VerticalAlignment="Top" Width="Auto" x:Name="Pager" 
                    Orientation="Horizontal">
            <Button Content="&lt;&lt;" Margin="0,0,3,0" x:Name="FirstButton" 
                    Click="GoFirst"/>
            <Button Content="&lt;" Margin="0,0,3,0" x:Name="BackButton" 
                    Click="GoBack"/>
            <TextBlock Text="Page" Margin="3,0,0,0" HorizontalAlignment="Center" 
                    VerticalAlignment="Center"/>
            <ComboBox Name="PageSelector" Margin="3,0,0,0" 
                      SelectionChanged="PageChanged"/>
            <Button Content="&gt;" Margin="3,0,0,0" 
                    x:Name="ForwardButton" Click="GoForward"/>
            <Button Content="&gt;&gt;" Margin="3,0,0,0"
                    x:Name="LastButton" Click="GoLast"/>
        </StackPanel>
    </Border>
</Grid>

 

And Here’s the code-behind

 

public partial class Page : UserControl
{
    private readonly PersonCollection masterCollection = 
        new PersonCollection();
    private int pageSize = 10;
    private int currentPage;
    private int maxPage;
 
    public Page()
    {
        InitializeComponent();
        Loaded += PageLoaded;
    }
 
    private void PageLoaded(object sender, RoutedEventArgs e)
    {
        // this line just creates test data - ignore;
        masterCollection.BuildTestData(1000,1000);
 
        masterCollection.CollectionChanged += (s, a) => SetPageData();
        SetPageSize();
        PageSize.ItemsSource = new List<int>(new[] {10, 25, 50});
        PageSize.SelectedIndex = 0;
        SetPageData();
    }
 
    private void SetPageSize()
    {
        maxPage = (int)Math.Ceiling((double)masterCollection.Count 
            / (double)pageSize);
        for (var i = 1; i <= maxPage; i++)
            PageSelector.Items.Add(i);
    }
 
    private void SetPageData()
    {
        MainGrid.DataContext = masterCollection
            .OrderBy(p => p.Name)
            .Skip(pageSize * currentPage)
            .Take(pageSize);
        BackButton.IsEnabled = FirstButton.IsEnabled = currentPage > 0;
        ForwardButton.IsEnabled = LastButton.IsEnabled = 
            currentPage+1 < maxPage;
        Total.Text = string.Format("Page {0} of {1} (Total : {2})", 
            currentPage+1, maxPage, masterCollection.Count);
        PageSelector.SelectedIndex = currentPage;
    }
 
    private void GoBack(object sender, RoutedEventArgs e)
    {
        currentPage--;
        SetPageData();
    }
 
    private void GoForward(object sender, RoutedEventArgs e)
    {
        currentPage++;
        SetPageData();
    }
 
    private void GoLast(object sender, RoutedEventArgs e)
    {
        currentPage = maxPage-1;
        SetPageData();
    }
 
    private void GoFirst(object sender, RoutedEventArgs e)
    {
        currentPage = 0;
        SetPageData();
    }
 
    private void PageChanged(object sender, 
        SelectionChangedEventArgs e)
    {
        currentPage = (int)PageSelector.SelectedItem-1;
        SetPageData();
    }
 
    private void PageSizeChanged(object sender, 
        SelectionChangedEventArgs e)
    {
        pageSize = (int) PageSize.SelectedItem;
        currentPage = 0;
        SetPageSize();
        SetPageData();
    }
}

 

As you can see, it’s pretty simple stuff.

Because the Silverlight DataGrid doesn't expose the built-in column sorting events, implementing sorting on the columns is a little more tricky – you’d have to re-template the headers and include a button who’s click event can invoke a custom sorting algorithm, which would be easy enough to implement should you want.

Any comments ? let me know.

(Source Files Below)

DemoPager.zip

Dean

Tags: ,

DataBinding | Silverlight

Comments


February 12. 2009 20:30
Jelen
Hi,

thankx a lot. This is a really very useful post.

JL


February 13. 2009 00:39
trackback
Trackback from Community Blogs

Silverlight Cream for February 12, 2009 -- #515


United States samcov 
February 14. 2009 07:39
samcov
I did a more complex pager, and used a combobox for the pages, but it failed miserably when the pages got large, way to difficult to navigat with.

My solution was to test the number of pages, and if it exceeded 50 pages, I removed the combobox and used a TextBox instead.  Of course the user could place a page in the textbos and hit enter to navigate.


United States MouB 
February 18. 2009 01:40
MouB
Hi, Thanx for the sample. Can you please explain the logic for  
private readonly PersonCollection masterCollection =         new PersonCollection(); class.
Please send the code behind for this class also.


February 19. 2009 07:41
Dean Chalk
Hi All

I have added a link to the source code at the bottom of the post (if it helps). The PersonCollection class is just an IEnumerable collecttion used as the data source for the Grid

Dean


India AAditya 
March 26. 2010 06:16
AAditya
Hey ur source code link is broken  guess.
is there any way i can get tat zip file?


March 27. 2010 08:31
Dean Chalk
Sorry the link was broken - is now fixed Smile


February 16. 2011 13:29
Matthias
Thanks for fixing the link!

Add comment


(Will show your Gravatar icon)

  Country flag

biuquote
  • Comment
  • Preview
Loading

FAO Comment Spammers : Please note that this blog is fully moderated by me personally and no comment spam will ever appear on this site.



RecentComments

Comment RSS
Disclaimer
The opinions expressed herein are my own personal opinions and do not represent my employer's view in anyway.

© Copyright 2012 Dean Chalk's Blog