Search code examples
winui-3itemscontrolvirtualizingstackpanel

WinUI 3 - Programmatic Scroll to Virtualized Item in ItemsControl (not ListView)


I'm making a custom ItemsControl subclass with a fairly typical template:

<Style TargetType="local:MyControl">
    <Setter Property="ItemsPanel">
        <Setter.Value>
            <ItemsPanelTemplate>
                <ItemsStackPanel Orientation="Vertical" /> 
                <!-- or VirtualizingStackPanel; not really sure 
                     why there are two different seemingly identical 
                     virtualization panels -->
            </ItemsPanelTemplate>
        </Setter.Value>
    </Setter>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="local:MyControl">
                <ScrollViewer x:Name="ScrollViewer"
                              VerticalScrollBarVisibility="Auto"
                              HorizontalScrollBarVisibility="Auto">
                    <ItemsPresenter />
                </ScrollViewer>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

where MyControl is a subclass of ItemsControl.

I need a way to programmatically scroll to an item, by content or even by index, that might not yet be realized on screen, where item heights are not uniform.

For ListView I can use ScrollIntoView but I don't want to derive from ListView as this comes with a lot of functionality I'm looking to replace/override.

In WPF VirtualizingStackPanel had BringIndexIntoViewPublic but that seems to be absent now and I can't find anything equivalent in WinUI VirtualizingStackPanel or ItemsStackPanel.

In the WinUI source code ListView.ScrollIntoView appears to be using a lot of internal/native functionality inside the ItemsPresenter that I can't access.

Is there any way to do this without subclassing ListView?


Solution

  • Have you tried the ItemsView control?

    <ItemsView x:Name="ItemsViewControl" ItemsSource="{x:Bind Items}" />
    

    then in code-behind:

    int targetIndex = 123;
    this.ItemsViewControl.StartBringItemIntoView(targetIndex, new BringIntoViewOptions());