Introducing the WinUI 2.6 Pager Controls

In this article we walk through a UWP app that demonstrates two new pagination controls that ship with the upcoming WinUI 2.6. The Windows UI 2.x Library is a project that’s factoring out the XAML UWP controls from the operating system into a NuGet package. New XAML controls and styles as well as backward compatible updates on existing native controls are rolled out via WinUI 2. This happens at a much higher pace than with the Windows 10 SDKs. WinUI 2 is allowing UWP developers to build and deploy apps that behave better on target platforms with different Windows 10 versions.

The next iteration of WinUI 2 will bring two new pagination controls: a traditional Pager control and a visual PipsPager control. The need for such a family of XAML pagination controls was raised in 2018, and today they are ready to use … well almost. WinUI v2.6. is currently in still prerelease. Make sure to check ‘include prerelease’ when looking for the NuGet package:

WinUI_2_PreRelease

Pagination controls make the most sense when they’re connected to large DataGrids. For the sake of simplicity our sample app just uses a FlipView with some images.

Pager Control

From the specifications we learn that the last official pagination control in XAML was the DataPager in … Silverlight. It’s good to see that this gap will finally be closed with a new XAML Pager control. Here’s the new Pager control in its simplest form – with its default display mode, and NumberOfPages and SelectedPageIndex bound to its associated FlipView:

<FlipView x:Name="ImageRepeater"
          ItemsSource="{x:Bind Pictures}" />
<!-- Default Display Mode -->
<winui:PagerControl NumberOfPages="{x:Bind Pictures.Count}"
                    SelectedPageIndex="{x:Bind ImageRepeater.SelectedIndex, Mode=TwoWay}" />

Here’s how it looks like – no surprises here:

Pager

By changing the DisplayMode to NumberBox you can trade the DropDown page selector for an editable NumberBox, more convenient when there are a lot of pages:

NumberBox

The third DisplayMode is named ButtonPanel and displays page numbers as a hyperlink, and an ellipsis if there are too many. Here’s the XAML:

<winui:PagerControl NumberOfPages="{x:Bind Pictures.Count}"
                    SelectedPageIndex="{x:Bind ImageRepeater.SelectedIndex, Mode=TwoWay}"
                    FirstButtonVisibility="Hidden"
                    LastButtonVisibility="Hidden"
                    NextButtonVisibility="Hidden"
                    PreviousButtonVisibility="Hidden"
                    DisplayMode="ButtonPanel" />

Here’s how this looks like:

ButtonPanelMode

In this configuration the Pager always displays a page number hyperlink to the previous, next, first, and last pages. It would be nice to hide the obsolete default arrow buttons for this. The API supports this, but unfortunately there’s this bug that prevents hide these buttons. The fix is not yet released.

The synchronization between the pagination control and the host of the pages can be configured via binding to (or programmatically updating) properties -like we did on this page- or by implementing event handlers on the button clicks – what we will do in the PipsPager sample.

WinUI is developed in the open, you find the (technical) documentation and C++ source code for the Pager control right here. The new Pager looks and feels totally as expected.

FlipView companion

The specifications for a glyph-based pagination control were issued long before the first implementation of the PipsPager. The description reminded us of a similar control that we wrote (many) years ago in the Windows 8 age: the FlipViewIndicator, a companion pagination control for … the FlipView. The control -basically a templated ListBox- ended up in Tim Heuer’s Callisto framework. For old times sake we dug up the source code and pasted it in the sample app. Here’s how the result looks like:

Indicator

We’re glad to see it still works nicely. Here’s how to use it in an app:

<FlipView x:Name="ImageRepeater"
            ItemsSource="{x:Bind Pictures}" />
<controls:FlipViewIndicator FlipView="{Binding ElementName=ImageRepeater}" /> />

For more details on its implementation, check this antique blog post.

PipsPager

Most web based image carousels use a pagination control made of dots, like this:

FlipCarousel

Pips are small but easily countable items, such as the dots on dominoes and dice, and that’s were PipsPager got its name from. It’s a row (or column) of dots -optionally extended with arrow buttons- that allows you to paginate. You find the full specs here.

Here’s its default look and feel in our sample app:

PipsPager

In an attempt to stretch the new control, we implemented a circular carousel: when the user reaches the end, the first item will reappear on the next navigation. To achieve this, we needed to override (or rather bypass) some of the PipsPager’s default behaviors. By default, the PipsPager

  • disables its ‘Previous’ button when the pip that corresponds to the first page is displayed,
  • does not react on clicking on the pip that corresponds to the displayed page, and
  • disables its ‘Next’ button when the pip that corresponds to the last page is displayed.

Instead, we built a carousel that

  • always keeps the pip for the selected page in the middle,
  • uses all other pips to navigate (slower with the more central pips, faster with the peripheral ones), and
  • implements circular (endless) navigation.

Here’s how it looks like:

PipsPagerCarousel

PipsPager supports this scenario: it allows setting NumberOfPages to a negative number to indicate an undefined or unknown number of pages, and it can hide its ‘Previous’ and ‘Next’ buttons. For the interaction, we’re using SelectedIndexChanged:

Here’s the XAML for our carousel PipsPager:

<FlipView x:Name="ImageRepeater"
            ItemsSource="{x:Bind Pictures}"
            SelectionChanged="ImageRepeater_SelectionChanged" />
<winui:PipsPager x:Name="Pager"
                    NumberOfPages="-1"
                    NextButtonVisibility="Collapsed"
                    PreviousButtonVisibility="Collapsed"
                    SelectedIndexChanged="Pager_SelectedIndexChanged"
                    MaxVisiblePips="5" />

To make sure that the pip for the first page never appears (it would not respond to clicking hence block the circular navigation) we decided to make the control not rotate between pages 1 and n (the number of images) but instead to make it rotate between n and 2n. So the PipsPager always believes he’s somewhere in the middle of the page collection.

Here’s the initialization:

Pager.SelectedPageIndex = Pictures.Count;

And here are the event handlers that implement change selection in the pager but also in its host. FlipView has its built-in navigation support, so it can change the selected item by itself, in which case we need to update the pager:

private void ImageRepeater_SelectionChanged(
	object sender, 
	SelectionChangedEventArgs e)
{
    // Keeps the selection in the middle of the pager.
    Pager.SelectedPageIndex = ImageRepeater.SelectedIndex;
}

private void Pager_SelectedIndexChanged(
	WinUI.PipsPager sender, 
	WinUI.PipsPagerSelectedIndexChangedEventArgs args)
{
    // Good that this doesn't create an infinite loop.
    Pager.SelectedPageIndex = Pager.SelectedPageIndex % Pictures.Count + Pictures.Count;
    ImageRepeater.SelectedIndex = Pager.SelectedPageIndex % Pictures.Count;
}

Just like the regular Pager this new PipsPager looks and feels as expected. There’s still some room to fix bugs and improve these controls: the official release of WinUI 2.6 is scheduled for next month. We’re happy with these two new pagination controls. It’s great to see the UWP ecosystem extended with good-working and good-looking essential controls.

Our sample app lives here on GitHub.

Enjoy!

Leave a Reply

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 )

Google photo

You are commenting using your Google 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 )

Connecting to %s