Silverlight Pagination

by Bron Skinner 10. April 2010 03:44

I know this topic is a little run of the mill and you can probably find built in solutions for pagination within one of the latest Silverlight toolkits but I thought I’d take a minute to review a custom pagination solution for Silverlight 3.

 

PaginationHelper<object> phelper = new PaginationHelper<object>(new ObservableCollection<object>(), 10);

dg.ItemsSource = phelper;

dg.SelectedIndex = 0;

stackpanel_pagination.Children.Add(phelper.GetPaginationControl());

 

Without getting too fancy I’ve developed a PaginationHelper class that extends an ObservableCollection<T>. In this way we can use the class itself as the DataContext or ItemsSource for the FrameworkElement in question.

 

public class PaginationHelper<T> : ObservableCollection<T>

    {

        private ObservableCollection<T> ItemsRef { get; set; }

        private int ItemCount { get; set; }

        private int PageItemCount { get; set; }

        private int TotalPages { get; set; }

        ...

 

So our basic steps for setting up pagination for a control:

 

a)      Instantiate the PaginationHelper()

b)      Set the DataContext/ItemsSource for our control

c)       Generate/Add our Pagination Control

 

 

a) Instantiate the PaginationHelper()

 

PaginationHelper<object> phelper = new PaginationHelper<object>(new ObservableCollection<object>(), 10);

 

private ObservableCollection<T> ItemsRef { get; set; }

private int ItemCount { get; set; }

private int PageItemCount { get; set; }

private int TotalPages { get; set; }

private int CurrentPage { get; set; }

private int IndexDisplay = 5;

private int ActiveIndexDisplay { get; set;}

private StackPanel sp;

private double opacity = 0.5;

 

public PaginationHelper(ObservableCollection<T> items, int pageItemCount)

{

            ItemsRef = items;

            ItemCount = ItemsRef.Count();

            PageItemCount = pageItemCount;

TotalPages = Convert.ToInt32(Math.Ceiling((double)ItemCount / (double)PageItemCount));

            CurrentPage = -1;

            ActiveIndexDisplay = 1;

}

 

Our Properties:

 

ItemsRef – stores the original DataContext/ItemsSource for reference.

ItemCount – Total Items in the ItemsRef (could just use ItemsRef.Count()).

PageItemCount – Items per “Page” of data.

TotalPages – TotalPages required to paginate contents of ItemsRef as per PageItemCount.

CurrentPage – Current active page.

IndexDisplay – Number Page shortcuts to display (pagination control element)

ActiveIndexDisplay – Group index of active IndexDisplay.

Sp – Our pagination control element parent

Opacity -  non-focused control element buttons (faded)

 

b) Set the DataContext/ItemSrouce for our Control

 

dg.ItemsSource = phelper;

dg.SelectedIndex = 0;

 

This Step is pretty simple, as the PaginationHelper is an ObservableCollection<T> in itself it can serve as the DataContext/ItemSource for your control.

 

c) Set the DataContext/ItemSrouce for our Control

 

stackpanel_pagination.Children.Add(phelper.GetPaginationControl());

 

This step calls the GetPaginationControl() function which generates a number of buttons that each call and load a page of items, and is returned as a FrameworkElement (StackPanel). The page the btn represents is stored as an int in its Tag property. The returned FrameworkElement can be placed really wherever you want. I placed mine underneath the DataGrid I set the PaginationHelper up for.

 

Digitalboon Silverlight Pagination

 

public FrameworkElement GetPaginationControl()

        {

            sp = new StackPanel();

            sp.Height = 21;

            sp.Orientation = Orientation.Horizontal;

 

           

            for (int i = 1; i <= TotalPages; i++)

            {

                Button btn_page = new Button();

                btn_page.Name = "page" + i.ToString();

                btn_page.Opacity = opacity;

                btn_page.Content = i.ToString();

    btn_page.Style =    (Style)App.Current.Resources["ButtonTabStyle"];

                btn_page.Width = 17;

                btn_page.Height = 17;

                btn_page.Tag = i;

                btn_page.MouseEnter += (s, e) =>

                    {

                        btn_page.Cursor = Cursors.Hand;

                        btn_page.Opacity = 1.0;

                    };

                btn_page.MouseLeave += (s, e) =>

                    {

                        btn_page.Cursor = Cursors.Arrow;

                        if ((CurrentPage) != (int)btn_page.Tag)

                        {

                            btn_page.Opacity = opacity;

                        }

                    };

                btn_page.Click += new RoutedEventHandler(btn_page_Click);

                sp.Children.Add(btn_page);

 

                if (i > IndexDisplay)

                {

                    btn_page.Visibility = Visibility.Collapsed;

                }

            }

 

 

            GetPage(1);

 

            return sp;

        }

 

When a page button is clicked  the GetPage function is called which takes the clicked button’s tag (int) property, retrieves a list of items representing the requested “page” of data, and reassigns those items to the entire class itself. As the PaginationHelper class extends ObservableCollection<T> (see INotifyPropertyChanged), the displayed data updates itself.

 

It’s worth noting as well that using a back and forward button users can manually iterate page loads in an ascending/descending pattern, and that multiple pages of pages can be setup such that iterating beyond the scope of the current displayed collection of pages will load the next set of pages:

 

private void SetPaginationVisibility()

        {

            if(sp != null)

            {

                for (int i = 1; i <= TotalPages; i++)

                {

                    if (sp.Children[i].GetType() == typeof(Button))

                    {

                        Button btn = (Button)sp.Children[i];

                        if (btn.Tag != null)

                        {

                            int high = IndexDisplay * ActiveIndexDisplay;

                            int low = high - IndexDisplay;

                            if ((int)btn.Tag > low && (int)btn.Tag <= high)

                            {

                                btn.Visibility = Visibility.Visible;

                            }

                            else

                            {

                                btn.Visibility = Visibility.Collapsed;

                            }

                        }

                    }

                }

            }

        }

 

Conclusion

 

There are a few things that could be cleaned up, there may be better ways of implemented a pagination solution, but all in all this turned out to be a pretty simple working pagination helper.

Tags:

Technical

Comments

6/29/2010 7:51:14 PM #

Please, can you PM me and tell me few more thinks about this, I am really fan of your blog...gets solved properly asap.

cure herpes United States |

6/30/2010 2:25:38 PM #

I really got a kick out of your article. I don't really have much to say in reply, I only wanted to comment to reply with wonderful operate. good luck in 2010.

fleas on humans United States |

6/30/2010 8:08:11 PM #

Took me long to learn all the commentaries, but I really loved the article. It demonstrated to be very functional to me and I am sure to all the commenters here! It�s always nice when you can not only be educated, but also involved! I�m sure you had fun publishing this article.

Acer Aspire One United States |

Powered by BlogEngine.NET 1.5.0.7
Custom theme for digitalboon.com by Bron Skinner

About the author

A Software Developer with a keen artistic sense, I’ve spent the last couple years working with predominantly Microsoft-based technologies developing web applications. The majority of this time has been spent building applications with SilverlightTM that forward some rather unique approaches to interface design. I am currently working full time.

 

 

Make sure to check out The Forge.


Download Resume