ItemsRepeater in ScrollViewer with no focusable elements ignores keyboard navigation
See original GitHub issueDescribe the bug If you’re trying to use PageDown/PageUp or Up/Down to scroll a ScrollViewer with an ItemsRepeater in it, it will not work if the ItemsRepeater contains no focusable elements. It can only be scrolled with the mousewheel or using the scrollbar handle directly.
Discovered while adding ItemsRepeater layouts to the Toolkit here
Steps to reproduce the bug
- Copy XAML into XAML Studio:
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:muxc="using:Microsoft.UI.Xaml.Controls"
mc:Ignorable="d">
<Page.Resources>
<converters:StringFormatConverter x:Key="StringFormatConverter"/>
</Page.Resources>
<ScrollViewer HorizontalScrollMode="Disabled"
VerticalScrollMode="Enabled"
HorizontalScrollBarVisibility="Disabled"
VerticalScrollBarVisibility="Auto" Margin="20">
<muxc:ItemsRepeater
ItemsSource="{Binding}">
<muxc:ItemsRepeater.Layout>
<muxc:UniformGridLayout Orientation="Horizontal"
MinItemWidth="200" MinItemHeight="200"
MinRowSpacing="16" MinColumnSpacing="8"
ItemsStretch="Uniform"
MaximumRowsOrColumns="4"
/>
</muxc:ItemsRepeater.Layout>
<muxc:ItemsRepeater.ItemTemplate>
<DataTemplate>
<Grid>
<Image Source="{Binding id, Converter={StaticResource StringFormatConverter}, ConverterParameter='https://picsum.photos/id/{0}0/200/200'}" Stretch="UniformToFill"/>
<Border Background="#99FFFFFF" VerticalAlignment="Bottom">
<TextBlock Text="{Binding title}" TextWrapping="WrapWholeWords"
Foreground="Black" Margin="4"/>
</Border>
</Grid>
</DataTemplate>
</muxc:ItemsRepeater.ItemTemplate>
</muxc:ItemsRepeater>
</ScrollViewer>
</Page>
2. And use the following DataSource (click here)
[
{
"userId": 1,
"id": 1,
"title": "quidem molestiae enim"
},
{
"userId": 1,
"id": 2,
"title": "sunt qui excepturi placeat culpa"
},
{
"userId": 1,
"id": 3,
"title": "omnis laborum odio"
},
{
"userId": 1,
"id": 4,
"title": "non esse culpa molestiae omnis sed optio"
},
{
"userId": 1,
"id": 5,
"title": "eaque aut omnis a"
},
{
"userId": 1,
"id": 6,
"title": "natus impedit quibusdam illo est"
},
{
"userId": 1,
"id": 7,
"title": "quibusdam autem aliquid et et quia"
},
{
"userId": 1,
"id": 8,
"title": "qui fuga est a eum"
},
{
"userId": 1,
"id": 9,
"title": "saepe unde necessitatibus rem"
},
{
"userId": 1,
"id": 10,
"title": "distinctio laborum qui"
},
{
"userId": 2,
"id": 11,
"title": "quam nostrum impedit mollitia quod et dolor"
},
{
"userId": 2,
"id": 12,
"title": "consequatur autem doloribus natus consectetur"
},
{
"userId": 2,
"id": 13,
"title": "ab rerum non rerum consequatur ut ea unde"
},
{
"userId": 2,
"id": 14,
"title": "ducimus molestias eos animi atque nihil"
},
{
"userId": 2,
"id": 15,
"title": "ut pariatur rerum ipsum natus repellendus praesentium"
},
{
"userId": 2,
"id": 16,
"title": "voluptatem aut maxime inventore autem magnam atque repellat"
},
{
"userId": 2,
"id": 17,
"title": "aut minima voluptatem ut velit"
},
{
"userId": 2,
"id": 18,
"title": "nesciunt quia et doloremque"
},
{
"userId": 2,
"id": 19,
"title": "velit pariatur quaerat similique libero omnis quia"
},
{
"userId": 2,
"id": 20,
"title": "voluptas rerum iure ut enim"
},
{
"userId": 3,
"id": 21,
"title": "repudiandae voluptatem optio est consequatur rem in temporibus et"
},
{
"userId": 3,
"id": 22,
"title": "et rem non provident vel ut"
},
{
"userId": 3,
"id": 23,
"title": "incidunt quisquam hic adipisci sequi"
},
{
"userId": 3,
"id": 24,
"title": "dolores ut et facere placeat"
},
{
"userId": 3,
"id": 25,
"title": "vero maxime id possimus sunt neque et consequatur"
},
{
"userId": 3,
"id": 26,
"title": "quibusdam saepe ipsa vel harum"
},
{
"userId": 3,
"id": 27,
"title": "id non nostrum expedita"
},
{
"userId": 3,
"id": 28,
"title": "omnis neque exercitationem sed dolor atque maxime aut cum"
},
{
"userId": 3,
"id": 29,
"title": "inventore ut quasi magnam itaque est fugit"
},
{
"userId": 3,
"id": 30,
"title": "tempora assumenda et similique odit distinctio error"
},
{
"userId": 4,
"id": 31,
"title": "adipisci laborum fuga laboriosam"
},
{
"userId": 4,
"id": 32,
"title": "reiciendis dolores a ut qui debitis non quo labore"
},
{
"userId": 4,
"id": 33,
"title": "iste eos nostrum"
},
{
"userId": 4,
"id": 34,
"title": "cumque voluptatibus rerum architecto blanditiis"
},
{
"userId": 4,
"id": 35,
"title": "et impedit nisi quae magni necessitatibus sed aut pariatur"
},
{
"userId": 4,
"id": 36,
"title": "nihil cupiditate voluptate neque"
},
{
"userId": 4,
"id": 37,
"title": "est placeat dicta ut nisi rerum iste"
},
{
"userId": 4,
"id": 38,
"title": "unde a sequi id"
},
{
"userId": 4,
"id": 39,
"title": "ratione porro illum labore eum aperiam sed"
},
{
"userId": 4,
"id": 40,
"title": "voluptas neque et sint aut quo odit"
},
{
"userId": 5,
"id": 41,
"title": "ea voluptates maiores eos accusantium officiis tempore mollitia consequatur"
},
{
"userId": 5,
"id": 42,
"title": "tenetur explicabo ea"
},
{
"userId": 5,
"id": 43,
"title": "aperiam doloremque nihil"
},
{
"userId": 5,
"id": 44,
"title": "sapiente cum numquam officia consequatur vel natus quos suscipit"
},
{
"userId": 5,
"id": 45,
"title": "tenetur quos ea unde est enim corrupti qui"
},
{
"userId": 5,
"id": 46,
"title": "molestiae voluptate non"
},
{
"userId": 5,
"id": 47,
"title": "temporibus molestiae aut"
},
{
"userId": 5,
"id": 48,
"title": "modi consequatur culpa aut quam soluta alias perspiciatis laudantium"
},
{
"userId": 5,
"id": 49,
"title": "ut aut vero repudiandae voluptas ullam voluptas at consequatur"
},
{
"userId": 5,
"id": 50,
"title": "sed qui sed quas sit ducimus dolor"
},
{
"userId": 6,
"id": 51,
"title": "odit laboriosam sint quia cupiditate animi quis"
},
{
"userId": 6,
"id": 52,
"title": "necessitatibus quas et sunt at voluptatem"
},
{
"userId": 6,
"id": 53,
"title": "est vel sequi voluptatem nemo quam molestiae modi enim"
},
{
"userId": 6,
"id": 54,
"title": "aut non illo amet perferendis"
},
{
"userId": 6,
"id": 55,
"title": "qui culpa itaque omnis in nesciunt architecto error"
},
{
"userId": 6,
"id": 56,
"title": "omnis qui maiores tempora officiis omnis rerum sed repellat"
},
{
"userId": 6,
"id": 57,
"title": "libero excepturi voluptatem est architecto quae voluptatum officia tempora"
},
{
"userId": 6,
"id": 58,
"title": "nulla illo consequatur aspernatur veritatis aut error delectus et"
},
{
"userId": 6,
"id": 59,
"title": "eligendi similique provident nihil"
},
{
"userId": 6,
"id": 60,
"title": "omnis mollitia sunt aliquid eum consequatur fugit minus laudantium"
},
{
"userId": 7,
"id": 61,
"title": "delectus iusto et"
},
{
"userId": 7,
"id": 62,
"title": "eos ea non recusandae iste ut quasi"
},
{
"userId": 7,
"id": 63,
"title": "velit est quam"
},
{
"userId": 7,
"id": 64,
"title": "autem voluptatem amet iure quae"
},
{
"userId": 7,
"id": 65,
"title": "voluptates delectus iure iste qui"
},
{
"userId": 7,
"id": 66,
"title": "velit sed quia dolor dolores delectus"
},
{
"userId": 7,
"id": 67,
"title": "ad voluptas nostrum et nihil"
},
{
"userId": 7,
"id": 68,
"title": "qui quasi nihil aut voluptatum sit dolore minima"
},
{
"userId": 7,
"id": 69,
"title": "qui aut est"
},
{
"userId": 7,
"id": 70,
"title": "et deleniti unde"
},
{
"userId": 8,
"id": 71,
"title": "et vel corporis"
},
{
"userId": 8,
"id": 72,
"title": "unde exercitationem ut"
},
{
"userId": 8,
"id": 73,
"title": "quos omnis officia"
},
{
"userId": 8,
"id": 74,
"title": "quia est eius vitae dolor"
},
{
"userId": 8,
"id": 75,
"title": "aut quia expedita non"
},
{
"userId": 8,
"id": 76,
"title": "dolorem magnam facere itaque ut reprehenderit tenetur corrupti"
},
{
"userId": 8,
"id": 77,
"title": "cupiditate sapiente maiores iusto ducimus cum excepturi veritatis quia"
},
{
"userId": 8,
"id": 78,
"title": "est minima eius possimus ea ratione velit et"
},
{
"userId": 8,
"id": 79,
"title": "ipsa quae voluptas natus ut suscipit soluta quia quidem"
},
{
"userId": 8,
"id": 80,
"title": "id nihil reprehenderit"
},
{
"userId": 9,
"id": 81,
"title": "quibusdam sapiente et"
},
{
"userId": 9,
"id": 82,
"title": "recusandae consequatur vel amet unde"
},
{
"userId": 9,
"id": 83,
"title": "aperiam odio fugiat"
},
{
"userId": 9,
"id": 84,
"title": "est et at eos expedita"
},
{
"userId": 9,
"id": 85,
"title": "qui voluptatem consequatur aut ab quis temporibus praesentium"
},
{
"userId": 9,
"id": 86,
"title": "eligendi mollitia alias aspernatur vel ut iusto"
},
{
"userId": 9,
"id": 87,
"title": "aut aut architecto"
},
{
"userId": 9,
"id": 88,
"title": "quas perspiciatis optio"
},
{
"userId": 9,
"id": 89,
"title": "sit optio id voluptatem est eum et"
},
{
"userId": 9,
"id": 90,
"title": "est vel dignissimos"
},
{
"userId": 10,
"id": 91,
"title": "repellendus praesentium debitis officiis"
},
{
"userId": 10,
"id": 92,
"title": "incidunt et et eligendi assumenda soluta quia recusandae"
},
{
"userId": 10,
"id": 93,
"title": "nisi qui dolores perspiciatis"
},
{
"userId": 10,
"id": 94,
"title": "quisquam a dolores et earum vitae"
},
{
"userId": 10,
"id": 95,
"title": "consectetur vel rerum qui aperiam modi eos aspernatur ipsa"
},
{
"userId": 10,
"id": 96,
"title": "unde et ut molestiae est molestias voluptatem sint"
},
{
"userId": 10,
"id": 97,
"title": "est quod aut"
},
{
"userId": 10,
"id": 98,
"title": "omnis quia possimus nesciunt deleniti assumenda sed autem"
},
{
"userId": 10,
"id": 99,
"title": "consectetur ut id impedit dolores sit ad ex aut"
},
{
"userId": 10,
"id": 100,
"title": "enim repellat iste"
}
]
Expected behavior Still able to scroll viewport with keyboard.
Screenshots
Version Info
NuGet package version: Microsoft.UI.Xaml 2.3.191129002
Windows 10 version | Saw the problem? |
---|---|
Insider Build (19624) | Yes |
November 2019 Update (18363) | |
May 2019 Update (18362) | |
October 2018 Update (17763) | |
April 2018 Update (17134) | |
Fall Creators Update (16299) | |
Creators Update (15063) |
Device form factor | Saw the problem? |
---|---|
Desktop | Yes |
Mobile | |
Xbox | |
Surface Hub | |
IoT |
Additional context If you wrap the Grid on line 29 in a Button, now you’ll see that PageUp/PageDown and Up/Down work.
Issue Analytics
- State:
- Created 3 years ago
- Reactions:1
- Comments:17 (10 by maintainers)
Top Results From Across the Web
Why doesn't keyboard input work for a ScrollViewer when ...
The OriginalSource on a KeyDown is set to the focused control, therefore the ScrollViewer ignores it when a child has the focus. The...
Read more >ScrollViewer keyboard navigation. - Forums
I want to scroll down to the next element that is invisible beyond the scrollviewer, or scroll up) the focus escapes to some...
Read more >UX | XAML Brewer, by Diederik Krols
ItemsRepeater is an ideal host for this: it's a WinUI element that ... it provides no policy around focus, selection, or user interaction....
Read more >ScrollViewer Class (System.Windows.Controls)
Gets a value indicating whether keyboard focus is anywhere within the element or its visual tree child elements. This is a dependency property....
Read more >ScrollViewer Class (Windows.UI.Xaml.Controls)
Represents a scrollable area that can contain other visible elements. ... in app UI for text input controls, if the system detects no...
Read more >Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start FreeTop Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
Top GitHub Comments
@StephenLPeters I think this is still a bug, it seems like the hosting
ScrollViewer
should still be getting the keyboard input to respond to the key events. It responds to Mouse Events (scroll wheel), so it’s really odd this isn’t keyboard accessible by default like the previous panel based models.We shouldn’t be putting extra onus on the developers using ItemsRepeater to have to do additional work to make their apps accessible, something like this should be just built-in.
The difference is that ItemsControl is a ‘Control’ that can take focus, have a template etc. but ItemsRepeater is not a control and does not take focus. ItemsRepeater is more like a Panel.