question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

ItemsRepeater in ScrollViewer with no focusable elements ignores keyboard navigation

See original GitHub issue

Describe 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

  1. 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 image

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.

FYI @ranjeshj @anawishnoff

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Reactions:1
  • Comments:17 (10 by maintainers)

github_iconTop GitHub Comments

3reactions
michael-hawkercommented, May 20, 2020

@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.

1reaction
ranjeshjcommented, May 21, 2020

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.

Read more comments on GitHub >

github_iconTop 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 >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found