Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature Proposal: PagerControl #60

Open
SavoySchuler opened this issue Dec 10, 2018 · 68 comments
Open

Feature Proposal: PagerControl #60

SavoySchuler opened this issue Dec 10, 2018 · 68 comments
Assignees
Labels
area-Pager feature proposal New feature proposal proposal-NewControl This proposal might involve creating a new control team-Controls Issue for the Controls team

Comments

@SavoySchuler
Copy link
Member

SavoySchuler commented Dec 10, 2018

The WinUI Team has opened a Spec for this feature.

Proposal: New UI Pagination Widget

Summary

This widget would provide a customizable pager UI, generic states, and generic events that can be configured to navigate pages for several view controls.

Rationale

  • Desired by community - tied with Make Grid Better for most engaged with issue on our repo.
  • Desired by 8/12 MVPs in survey.
  • Several UI teams actively interested in parallel development.

The absence of a standard UI pager control, last seen as DataPager in Silverlight, has been a pain point in both WPF and UWP that has forced a variety of unfavorable workarounds for developers. Inclusion of this control in UWP would resolve an ecosystem gap and enable developers to efficiently deliver UI paging experiences in their applications. Through XAML Islands, it may also provide an opportunity to benefit WPF developers working with DataGrid or ListView. The scope of this proposal is not provide a data paging solution at this time but to start with UI paging as a foundation on top of which data paging may be later integrated.

Requirements

# Feature Priority
1 Can support the option to have multiple display modes as the core navigation component (NumberBox, ComboBox, Button panel). Must
2 Can have optional text and/or glyphic bookend navigation controls (First/Last, Next/Back, none). Must
2 Can be used to page GridView, ListView, DataGrid, and ItemsRepeater. Must
4 Support for non-data binding/indeterminate page count solutions. Must
5 Designed to support later possible integrated data paging component. Must

Important Notes

Here are how the three configurations could look:

ComboBox configuration

A pager control with the following components in left-to-right order: a "< Prev" button, text that specifies "Page," a ComboBox that displays the current page and can be changed to index to a new page, text reading "of 10" that indicates how many pages there are, and a "Next >" button.

NumberBox configuration:

A pager control with the following components in left-to-right order: a back button that shows an arrow pointing left, a NumberBox that displays the current page and can be changed to index to a new page, text reading "of 5" that indicates how many pages there are, and a next button that shows an arrow point right.

Button panel configuration:

A pager control with the following components in left-to-right order: a "first page" button, a "previous page" button, numerical buttons for pages one through ten with an ellipsis omitting pages six through nine, a "next page" button, a "last page" button.

Usage Examples

Using a button panel as the display mode.

image

<UserControl x:Class="DataPagerSample.MainPage">
   <Grid x:Name="LayoutRoot" RowDefinitions="*,Auto">
        <GridView x:Name="gridView1" ... />
	<muxc:UIPager x:Name="uiPager1"
            Source="{Binding}"
	    LastButton="AlwaysVisible"
            FirstButton="AlwaysVisible"
            NumberOfIndicesShowing="7"
	    EllipsisMaxBefore="5"
	    EllipsisMaxAfter="1"
            EllipsisShowBounds="True" />
    </Grid>
</UserControl>

Using an editable ComboBox as the display mode.

image

<UserControl x:Class="DataPagerSample.MainPage">
    <Grid x:Name="LayoutRoot" RowDefinitions="*,Auto">
        <GridView x:Name="gridView1" ... />
	<muxc:UIPager x:Name="uiPager1"
	    Source="{Binding}"
	    DisplayMode="EditableComboBox"
	    NextButtonText="Prev"
	    PreviousButtonText="Next"
	    PrefixText="Page"  
	    TotalNumberOfPages="10" />
    </Grid>
</UserControl>

Visual Components

Component Notes
DisplayMode * Used to set either a button panel (default) or an editable ComboBox as the indexing component.
* When set to be a button panel, the number of visible indices can be specified.

image          image
LastButton * Button displaying text and/or glyph indicating that the user may navigate to the last index.
* Automatically disabled when at last index.
* Can be set to not be visible when at the last index.

image
FirstButton * Button displaying text and/or glyph indicating that the user may navigate to the first index.
* Automatically disabled when at first index.
* Can be set to not be visible when at the first index.

image
NextButton * Button displaying text and/or glyph indicating that the user may navigate to the next index.
* Automatically disabled when at last index.
* Can be set to not be visible when at the last index.

image
PreviousButton * Button displaying text and/or glyph indicating that the user may navigate to the previous index.
* Automatically disabled when at first index.
* Can be set to not be visible when at the first index.

image
Ellipsis * Button, often reading "...", used between indexes and before or after the first/last index to indicate an accessible but omitted range of indexes.
* MaxBefore and MaxAfter properties can be used to set how many indices appear between the current page and the ellipsis before/after it.
* Visibility of the first/last index can be disabled.
* Only visible when using button panel as the display mode.

image
PrefixText * Text displayed before the editable ComboBox indexing component.

image
NumberOfPages * When a total number of indices (N) is given, this suffix string will appear after the editable ComboBox indexing component and read "of N". Localization will put "N" where it should be in a given language.

image

Accessibility

State Action Narrator
UI pager is first focused on by tabbing Focus defaults to the next page button if available (current page otherwise) after announcing accessible name of UI pager. “Page selector. Next page is N."
UI pager is tabbed through Tab Button:
Will go through all actionable items in order without regard to groups.

Arrow keys:
Will be able to explore groups in the specified directions. Pressing the down arrow key at the bottom of the ComboBox will wrap the user to the top.

Escape:
Will escape UI pager.

Enter and Spacebar:
Will select the component focused on.

Home:
Will move focus to "go back" elements. In the ComboBox, it will jump the user to the first index.

End:
Will move focus to "go forward" elements. In the ComboBox, it will jump the user to the last index.
Narrator will announce an accessible name of the visual component. Ex:

“first page button”

“previous page button”

“1st page”

“current page”

"page selection drop down menu: current page is 1”

API Surface Example

<PagerControl
    DisplayMode = { Auto | ComboBox | NumberBox | ButtonPanel }
    NumberOfIndicesShowing = { int }
    LastButton = { Auto | AlwaysVisible | HiddenOnLast | None } 
    LastButtonGlyph = { string }
    LastButtonText = { string }
    LastButtonStyle = { string }
    FirstButton = { Auto | AlwaysVisible | HiddenOnFirst | None }
    FirstButtonGlyph = { string }
    FirstButtonText = { string }
    FirstButtonStyle = { string }
    NextButton = { Auto | AlwaysVisible | HiddenOnLast | None } 
    NextButtonGlyph = { string }
    NextButtonText = { string }
    NextButtonStyle = { string }
    PreviousButton = { Auto | AlwaysVisible | HiddenOnFirst | None }  
    PreviousButtonGlyph = { string }
    PreviousButtonText = { string }
    PreviousButtonStyle = { string }
    EllipsisEnabled = { True | False }
    EllipsisMaxBefore = { int }
    EllipsisMaxAfter = { int }
    EllipsisShowBounds = { True | False }
    PrefixText = { string }  
    NumberOfPages = { int } >
</PagerControl>

Related

Proposal: Data Paging for PagerControl #268

@SavoySchuler SavoySchuler self-assigned this Dec 10, 2018
@SavoySchuler SavoySchuler added the feature proposal New feature proposal label Dec 10, 2018
@SavoySchuler SavoySchuler changed the title Feature Proposal: New UI Pagination Control Feature Proposal: PagerControl Dec 10, 2018
@ryandemopoulos
Copy link
Member

Made a few minor updates Savoy:

  • Added a hyperlink to the WCT DataGrid control, since it's part of a separate library
  • Updated the ""s and #s to be string and int respectively, in the code snippet
  • Replaced ViewPager with PagerControl, to match the title.

@kmgallahan
Copy link
Contributor

kmgallahan commented Dec 11, 2018

Great proposal.

I feel like with this display mode:

Numeric Display Mode

The First & Last buttons are redundant, so the default state could be None. That is assuming the first and last index are displayed by default, which seems to be the case: "Visibility of the first/last index can be disabled."

Regarding these open questions:

Should numerals in the button panel be replaceable with glyphs?

Seems to be a popular design choice, and I'd like to have the option.

Will some scenarios require the glyphs to not be clickable (buttons not needed and spacing may be narrowed)?

I'm sure some designers might want this option, but as a user I pretty much always dislike when I can't interact with them.

Should a timer and wrap-around feature be added?

Would be useful, but low priority IMO.

@michael-hawker
Copy link
Collaborator

I think it's important to highlight the 'not in scope' part in the rationale a bit better, as that was my first question/thought:

The scope of this proposal is not provide a data paging solution at this time but to start with UI paging as a foundation on top of which data paging may be integrated.

So, to clarify, this is a UI element only, but the developer is still responsible for manipulating the source to the GridView/ListView/etc... to make the pages work? It'd be good to provide a code sample here about how that's expected to be accomplished to see how this scenario would work end-to-end.

(Also, in the sample XAML, don't indent the pager control as it makes it look like it goes in the GridView component not next to it in the tree.)

@SavoySchuler
Copy link
Member Author

SavoySchuler commented Dec 12, 2018

@kmgallahan Great feedback, thank you! I agree it reduces redundancy to only have the LastButton/FirstButton or the range bounds visible. Upon reviewing several example implementations, it appears most actually have neither - which I will update the default behavior to be. I have left the redundancy of these optional components in the Usage Examples to help communicate what they are and how they look.

I agree that glyph panels are a popular design. I am not sure if I would if it would make more sense to have "GlyphPanel" as a DisplayMode, subclass of a pager parent, or just as an option to replace numerals with glyphs in the ButtonPanel DisplayMode. When you think of wanting to create a glyph panel for these kind of displays, are one of these options where you would think to start?

@SavoySchuler
Copy link
Member Author

SavoySchuler commented Dec 12, 2018

@michael-hawker Thank you for the great feedback! That is correct - by developing both sides of this solution as distinct but cooperative components, we can allow PagerControl to be more flexible for developers. I will refine this proposal with clear examples that show end-to-end solutions for these scenarios and I will tag you in a comment when new Usage Examples are posted. Thanks for the code catch, I have it updated!

@kmgallahan
Copy link
Contributor

kmgallahan commented Dec 12, 2018

@SavoySchuler My initial thought was that a subclass would somewhat defeat the purpose of the DisplayMode property. However, looking over the properties & proposed features, it seems many of them would only be applicable to a particular display mode.

GlyphMode would not use:

  • NumberOfIndicesShowing (assuming most use cases involve a small fixed number of glyphs)
  • LastButton * et al.
  • FirstButton * et al.
  • Ellipsis * et al.
  • PrefixText
  • NumberOfPages

While it would be the exclusive use case for a built-in timer function (based on 'normal' design choices of not auto-cycling through paged data).

Similarly ButtonPanel mode doesn't need:

  • PrefixText
  • NumberOfPages

and similar situation for the EditableComboBox mode.

So using a DisplayMode property vs. base class / subclass approach would result in a rotating set of irrelevant properties, depending on the selected mode. Not that having a subclass for every mode seems like an amazing approach either... classic programming dilemma.

@SavoySchuler
Copy link
Member Author

@kmgallahan I agreed! The button panel and combobox scenarios certainly have more in common with each other than either of them do with glyphs. Consider a pager base class with two subclasses: one for glyphs and another for both ButtonPanel + ComboBox (which uses the display mode property to set the core indexing component). Does this feel like an ideal compromise to pair the two display modes with common properties as one sublass and to share all the methods and events common to all three from the base class? I feel like this the reduces redundancy of a sublcass-only approach and adds clarity by removing atavistic properties left by the DisplayMode only approach, but I also want to make sure I am not adding complexity with out benefit.

@kmgallahan
Copy link
Contributor

kmgallahan commented Dec 12, 2018

@SavoySchuler Seems like a good compromise yes. Having the base class also provides an opportunity for reuse in the future, if there were ever some 4th/5th modes that one might want to introduce (without having to always propose more DisplayModes and bloating the single class with properties).

@betrue-final-final
Copy link
Member

Some interesting iterations here. I just want to add that you want to be sure to think about freeway scenarios for both sighted and blind users. The numbers are definitely more helpful for both the blind and sighted, however the combo box is much easier to understand for blind users. That said, I would not offer the version with just pips instead of numbers, and I would suggest making the combobox version default.

@SavoySchuler
Copy link
Member Author

@betrue-final-final Thank you for this feedback! I will set the default display mode to be ComboBox.

Regarding the glyphic display mode, do you think it would it be an appropriate compromise for it to visually display pips but read out numerals to narrator? In this case, you could think of them as the same display mode that differs only in whether glyphs or numerals are visually displayed on the button panel but all other accessiblity navigation and output would be the same. This glyphic display pops up in a lot of store applications and are often custom implementations that are not accessibility inclusive. I believe we have an opportunity to create an accessible version of this control where there have previously been few. Please let me know if you see things differently as inclusion of the glyphic display mode is still an open question. Thanks again for starting this conversation!

@micahl
Copy link
Contributor

micahl commented Dec 14, 2018

An additional open question I think would be great to have answered from the community is whether anyone has encountered situations other than a FlipView UX that required the use of the dots / glyphs? The FlipView's design guidance refers to it as a type of context indicator. If it's only used with a FlipView UX then should FlipView just provide that as a built-in option?

@SavoySchuler
Copy link
Member Author

@micahl Great question! I have updated the Open Questions section to include this.

@LucasHaines
Copy link

LucasHaines commented Dec 18, 2018

Is this something we could use for Forms? See the last comment in Issue #82.

@mrlacey
Copy link
Contributor

mrlacey commented Dec 18, 2018

@LucasHaines I assume you mean this comment? (As "last" will potentially change.) As it's just a UI element with no functionality, I see no reason why it couldn't be used with a form. Why you'd want it to be used for all forms, I'm not sure.

@SavoySchuler Regarding the open question about custom glyphs for indicators, I have known brands who were really keen to do that customization for added brand identity flourishes. I have also seen different icons used for different pages but that seems like a very niche need and not something I'd encourage by prioritizing.

@mrlacey
Copy link
Contributor

mrlacey commented Dec 18, 2018

How will this control react to a lack of space for all sub-elements having space to be displayed? -- Will the number of options displayed be reduced? Will the control be clipped if it overflows the available space?
Will the space between sub-elements be further padded when there is additional space to expand into?

@mdtauk
Copy link
Contributor

mdtauk commented Dec 18, 2018

I think when talking about the forms control, a pagination control of this complexity would not be ideal, and could encourage complexity where it need not be.

When I commented on pagination I was thinking more about the Xbox or Windows OOBE style of pagination or grouping of steps - so you see how far into the form process you are.

image

image

Maybe this type of simple pagination can be part of the control proposed - perhaps it could be seen as a primitive used by various controls - but pagination as a form of progress indication.

@SavoySchuler
Copy link
Member Author

SavoySchuler commented Dec 18, 2018

@LucasHaines, @mrlacey is correct that this control would accomodate your scenario and the core functionality of the ones surfaced by by @mdtauk (noting we would need to expand on the visual styling to meet these scenarios fully).

@mrlacey Your question is one that I am actively exploring. I am starting to believe that offering this widget without built-in data paging capabilities will not be enough to fully enable the experiences we would like to help developers create for their customers. I am thinking that this proposal might benefit from being expanded to include an optional data paging component that would handle data paging, displaying content, and window resizing. Leaving this data paging component optional would also still allow for more advanced and custom scenarios that make use of only the UI component like @LucasHaines might need for forms or @mdtauk might need for grouping set up steps.

@SavoySchuler
Copy link
Member Author

@mrlacey Thanks for your feedback on the glyphic display mode! Do you happen to have any of those examples of brands using custom glyphs that you can point me toward?

@micahgodbolt
Copy link
Member

Hey everyone. As we're working on the pagination control over in Fabric, we were considering building a more primitive "pager" control that is mostly this:

image

It'd maintain state, have first/prev/next/last controls, have a public interface for changing state etc, but wouldn't be concerned with how the paging view was represented (numbers, numbers with ellipsis, glyphs, or even pivot buttons). It would also include an optional child view (above or below) to render content based on current page, making it foundation for carousels, FREs, pivots etc.

Do you typically do similar abstractions in UWP? Is this something you're considering with this control?

@mrlacey
Copy link
Contributor

mrlacey commented Jan 7, 2019

@SavoySchuler Sorry, nothing public I can point to anymore. Maybe it's a trend that's passed now but I have memories of re-templating lots of low-level things like a progress ring so it used different shapes, instead of circles, etc.
When this issue came up I immediately thought of designers I've worked with in the past who would love the ability to easily change these glyphs.

@mdtauk
Copy link
Contributor

mdtauk commented Jan 7, 2019

If the glyphs for each button are exposed as a DependencyProperty with default values set for the SegoeMDL2 fonts - then creating a style with new FontFamily and Glyph values set should provide the flexibility and ease of change devs who need it, would want.

@YuliKl
Copy link

YuliKl commented Jan 8, 2019

It would also include an optional child view (above or below) to render content based on current page, making it foundation for carousels, FREs, pivots etc.
Do you typically do similar abstractions in UWP?

@micahgodbolt - No, UWP controls tend to be complete and ready to use out of the box rather than being smaller building blocks. Molecules rather than atoms, if that analogy makes sense. We have a Pivot control which is in no way related to the proposed PagerControl.

@micahgodbolt
Copy link
Member

@YuliKl totally understand. In React we're always looking for ways to reuse smaller controls, or to breaking up a single control into smaller reusable pieces. As i'm less familiar with UWP, I'm not sure how well the platform supports that type of sharing.

@micahl
Copy link
Contributor

micahl commented Jan 8, 2019

I think you'd find in practice that there's more similarity than differences. Bigger controls (molecules) that contain a lot of built-in policy are made up of smaller controls (atoms) that have less policy. Molecules are easy to use. Atoms are more flexible and simple. Expectations around a given scenario and its similarity to others heavily influence the approach taken to solve it. @micahgodbolt It would be useful to understand what scenarios you've encountered.

@micahgodbolt
Copy link
Member

@micahl When I look at pager controls I see three things, 1 stateful container with controls to go to first, prev, next last, and secondly a view to display the current page and give UI for selecting the page, and lastly an optional content region to render content associated with that page. So if we built a paging control that only worried about state, the inner and outer view, and controls/public methods for changing the page, then we'd have a really flexible control that could be used to create carousels, first run experiences, pivots, and pagination.

This way everything that was built on this control would share a common public interface, and could easily be customized to add functionality, or change the way in which the UI is displayed. It also means that when we go to add functionality, we can add it in one place and everything else gains the same functionality. We already have too many similar controls where a feature is added to one of them, and then someone asks for that feature to be added to others.

Great example, we have an underlined TextField variant (just an underline, no box border), and there's a request to add that variant to datepicker, dropdown and comobobox (it's already added to search). microsoft/fluentui#5631

So you can see it would have been better for all of those controls to be built off of TextField, so that they could each benefit from that design variant.

@StephenLPeters
Copy link
Contributor

@chingucoding can you comment on this issue so that I can assign it to you?

@marcelwgn
Copy link
Contributor

Sure thing.

@michael-hawker
Copy link
Collaborator

michael-hawker commented Sep 25, 2020

@YuliKl @MarissaMatt yeah, different scenarios and use-cases, but still can be covered by this same control/pattern.

I think it's important to consider alternatives when designing controls to make sure they can provide for a broad range of experiences and ensure those experiences are consistent across apps.

I've only seen the pager in grid like scenarios in the mock-up, but I see driving page navigation in reading apps or document editors as an equally valid use-case.

Driving the FlipView control was actually one of the initial things that drove this feature request IIRC.

@gabbybilka
Copy link
Member

For anyone interested in pip pagination (oriented vertically and horizontally) leveraging PagerControl, please continue the discussion in this recently opened issue #3464. Thanks!

@marcelwgn
Copy link
Contributor

Are there plans to also provide this control in WinUI 3?

@jingliancui
Copy link

Hi All, do you know is this spec will plan for winui3? Or any others 3rd party nuget we can use for winui3? Thanks.

@marcelwgn
Copy link
Contributor

@jingliancui That would be something I could work on. Are you using C# or C++?

@jingliancui
Copy link

Hi @marcelwgn , thanks your kindly response, I'm using C# MAUI and WinUI3.

@marcelwgn
Copy link
Contributor

marcelwgn commented Jan 28, 2024

Thank you @jingliancui, so would a WinUI 3 only solution help you then?

@jingliancui
Copy link

Thanks @marcelwgn is it easy for you to import it to winui3? If yes then please.Thanks

@marcelwgn
Copy link
Contributor

I'll give it a shot to write a lib that only contains PagerControl so it at least can be imported when you need it @jingliancui

@jingliancui
Copy link

If you are get familiar with maui then it would be great that the ui can be shared to Mac, Win,Android,iOS, iPadOS.

@jingliancui
Copy link

Thank you so much, if Winui3 take you fewest effort, then winui3 is ok. Thanks again

@jingliancui
Copy link

Hi @marcelwgn Do you have the repo link to share? So I can try to help if need. Thanks.

@marcelwgn
Copy link
Contributor

Hi @jingliancui thank you for asking, I'm afraid to say I don't have a repro (or NuGet) link yet but I'll be sure to let you know once I have something. Thank you for your interest in this!

@marcelwgn
Copy link
Contributor

Hi @jingliancui, I've ported it over to C# and published the control to NuGet now. You can find the repo here: https://github.com/marcelwgn/PagerControlPolyfill

@jingliancui
Copy link

Thank you so much @marcelwgn !

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-Pager feature proposal New feature proposal proposal-NewControl This proposal might involve creating a new control team-Controls Issue for the Controls team
Projects
None yet
Development

No branches or pull requests