Implementing Pagination in Windows Store Apps Using FlipView – Boredom Challenge Day 25

Standard

If you have a large amount of items in a list, it is quite common to divide them into smaller sized lists (pages) in order to display them effectively. This is called pagination, and it is done for several (obvious) reasons: You won’t have to get all of the items at the same time (which may cause quite a performance hit while fetching and displaying the data) and the user won’t have to rummage through thousands of items to find the one s/he wants.

1

In Windows Store Apps, we wouldn’t normally need to implement such a feature due to the design principles (GridView, combined with SemanticZoom can work wonders in this case, check this article if you want to know more). However, this only eliminates the user’s side of the problem: You would still need to get all the items from your database at the same time. And although you can implement infinite scrolling with GridView (more items are incrementally loaded as user scrolls), you may not want the user to scroll at all and wish to display a set number of items where the user can navigate to the next set or the previous set (just like pagination explained above).

So, we want to be able to get a smaller number of items, load them only when the user wishes to view them, and let the user “flip” them like a turning a page. Seems like a job for.. FlipView! Yes, we can use a FlipView control to provide this functionality, by using a custom UserControl in its ItemTemplate and jumping through a few hoops.

A screenshot from the example app we'll make.

A screenshot from the example app we’ll make.

In this article, we’ll create an app that will use a FlipView for pagination. We’ll create it in such a way that in the beginning, we would only need to tell the FlipView how many pages we will have, and then load the items within the UserControl in FlipView’s ItemTemplate when a specific page is selected. Therefore, we will get the items user will view only when they will be used.

Alright then, we start with creating our blank Windows Store app project in Visual Studio.

3

Before starting, however, I need to warn you that we’ll have to arrange the sizes of the FlipView and GridView items carefully based on the number of items we wish show at once. I’ve set the sizes in this example to show 4 rows and 7 columns of 100×100 sized items in one FlipView page. If you wish to create your own design, you’ll need to do some fine tuning with the sizes.

We’ll first create the user control that will be used in the FlipView’s ItemTemplate (which will display one “page” of data).

4

Our user control will include a GridView used to display the items, and a ProgressRing to show that the items are being loaded (we’ll simulate this effect using a timer). Therefore, our FlipViewPageUserControl.xaml file will look like this:

    <Grid>
        <GridView x:Name="GridViewMain" Margin="55,0,45,0">
            <GridView.Resources>
                <DataTemplate x:Key="GridViewMainDataTemplate">
                    <Grid Width="100" Height="100" Background="#FF3E9547">
                        <TextBlock Text="{Binding}" VerticalAlignment="Center" FontSize="15" FontFamily="Segoe Uı" FontWeight="Light" TextWrapping="Wrap" TextAlignment="Center"/>
                    </Grid>
                </DataTemplate>
            </GridView.Resources>
            <GridView.ItemTemplate>
                <StaticResource ResourceKey="GridViewMainDataTemplate"/>
            </GridView.ItemTemplate>
        </GridView>
        <ProgressRing x:Name="ProgressRing" Width="50" Height="50"/>
    </Grid>

And in FlipViewPageUserControl.xaml.cs, we’ll add the following code which will load the items when the user control is shown:

        int page;
        DispatcherTimer dispatcherTimer;

        public FlipViewPageUserControl()
        {
            this.InitializeComponent();
            this.Loaded += FlipViewPageUserControl_Loaded;
        }

        void FlipViewPageUserControl_Loaded(object sender, RoutedEventArgs e)
        {
            page = (int)this.DataContext;
            dispatcherTimer = new DispatcherTimer();
            dispatcherTimer.Interval = new TimeSpan(0, 0, 1);
            dispatcherTimer.Tick += dispatcherTimer_Tick;
            if (page == 0)
            {
                SwitchedToThisPage();
            }
        }

        void dispatcherTimer_Tick(object sender, object e)
        {
            ProgressRing.IsActive = false;
            page = (int)this.DataContext;
            dispatcherTimer.Stop();
            int startItem = page * 28;
            int finishItem = startItem + 28;
            List<string> items = new List<string>();
            for (; startItem < finishItem; startItem++)
            {
                items.Add(String.Format("Item {0}", startItem));
            }
            GridViewMain.ItemsSource = items;
        }

        public void SwitchedToThisPage()
        {
            if (dispatcherTimer != null)
            {
                ProgressRing.IsActive = true;
                dispatcherTimer.Start();
            }
        }

        public void SwitchedFromThisPage()
        {
            GridViewMain.ItemsSource = null;
        }

Ok, let’s see what we have here.

In FlipViewPageUserControl, we have a public function called SwitchedToThisPage that we will call when the UserControl is visible (we’ll handle it in FlipView’s SelectionChanged event). This SwitchedToThisPage function is where we will get our data: We start a timer that simulates us getting our data from the database, and in that timer’s tick function we get the items based on which page we are showing (we will bind the page number to our user control, so we get it from its DataContext). This way, if we’re in the first page, we get items 1-28, on second page, items 29-56, and so on.

Then, in SwitchedFromThisPage, we empty the GridView. This function will be called when the user selects another page. We have to do this, because FlipView has a feature called virtualization, that makes it recycle its items for performance. Therefore, even if we have 15 pages, we’ll have only 3 FlipViewPageUserControls, so when we are done with a UserControl we reset its contents. That is also why we get the page number twice (once in Loaded, once in dispatcherTimer_Tick).

Also note that in FlipViewPageUserControl_Loaded, we get the items if it is the first page. This is because when we do the data binding, the selection changed event of FlipView will call our SwitchedToThisPage function before the Loaded event is fired. This way, we make sure we get the first items when the user control is loaded.

Anyway, that’s all for the user control. At the next step, we’ll put the FlipView in MainPage.xaml (Don’t forget to build the project once so FlipViewPageUserControl will be added to the Toolbox):

    <Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
        <FlipView x:Name="FlipViewMain" HorizontalAlignment="Left" Margin="100,100,0,0" Width="885" VerticalAlignment="Top" Height="470" SelectionChanged="FlipViewMain_SelectionChanged">
            <FlipView.Resources>
                <DataTemplate x:Key="FlipViewMainDataTemplate">
                    <local:FlipViewPageUserControl />
                </DataTemplate>
            </FlipView.Resources>
            <FlipView.ItemTemplate>
                <StaticResource ResourceKey="FlipViewMainDataTemplate"/>
            </FlipView.ItemTemplate>
        </FlipView>
    </Grid>

Now, we only need to fill the page numbers to the FlipView, and then call the related FlipViewPageUserControls’ SwitchedToThisPage and SwitchedFromThisPage functions within FlipView’s SelectionChanged event:

        public MainPage()
        {
            this.InitializeComponent();
            this.Loaded += MainPage_Loaded;
        }

        void MainPage_Loaded(object sender, RoutedEventArgs e)
        {
            for (int i = 0; i < 8; i++)             {                 FlipViewMain.Items.Add(i);             }         }         private void FlipViewMain_SelectionChanged(object sender, SelectionChangedEventArgs e)         {             if (e.AddedItems.Count > 0)
            {
                var flipViewItem = FlipViewMain.ItemContainerGenerator.ContainerFromIndex(FlipViewMain.SelectedIndex);
                FlipViewPageUserControl userControl = FindFirstElementInVisualTree<FlipViewPageUserControl>(flipViewItem);
                userControl.SwitchedToThisPage();
            }
            if (e.RemovedItems.Count > 0)
            {
                var flipViewItem = FlipViewMain.ItemContainerGenerator.ContainerFromItem(e.RemovedItems[0]);
                FlipViewPageUserControl userControl = FindFirstElementInVisualTree<FlipViewPageUserControl>(flipViewItem);
                userControl.SwitchedFromThisPage();
            }
        }

        private T FindFirstElementInVisualTree<T>(DependencyObject parentElement) where T : DependencyObject
        {
            var count = VisualTreeHelper.GetChildrenCount(parentElement);
            if (count == 0)
                return null;

            for (int i = 0; i < count; i++)
            {
                var child = VisualTreeHelper.GetChild(parentElement, i);

                if (child != null && child is T)
                {
                    return (T)child;
                }
                else
                {
                    var result = FindFirstElementInVisualTree<T>(child);
                    if (result != null)
                        return result;

                }
            }
            return null;
        }

Here, we add the pages in MainPage_Loaded event, and in FlipViewMain_SelectionChanged, we determine which page we navigated to and which page we navigated from. The “FindFirstElementInVisualTree” function allows us to get in the ItemTemplate of the FlipView and reach our user control.

Our app is ready to be run now. If you run it, you’ll see that you can go through the pages and a page’s content will only be loaded when you view it.

5

6

Although we haven’t done it in the example, you can take this a step further and add a control below the FlipView which will show the current page number and/or allow the user to jump to a specific page (since we can directly set FlipView’s SelectedIndex property).

Yes, it requires more work than other alternatives but if you really want pagination, this is how you can do it. 🙂

You can get the source code of our example here.

Thank you for reading.

Advertisements

4 thoughts on “Implementing Pagination in Windows Store Apps Using FlipView – Boredom Challenge Day 25

  1. burhan

    Güzel. Sağolun. Bu flipview i çok uzun bir yazıyı sayfalamak için kullanabilir miyiz. Eğer evet ise nasıl?

  2. Ej

    how about putting event handler to the FlipView items? Example when i click Item 99 it will product a popup saying Hi, etc.?

Comment

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s