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
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="<<" Margin="0,0,3,0" x:Name="FirstButton"
Click="GoFirst"/>
<Button Content="<" 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=">" Margin="3,0,0,0"
x:Name="ForwardButton" Click="GoForward"/>
<Button Content=">>" 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