I want to create a horizontally scrollable ListView with a selection indicator located at the top or bottom.
Can I achieve that by restyling ListViewItemPresenter or anyhow else reusing it?
3 Answers
I'm not sure if you can restyle ListViewItemPresenter.
The selection indicator is a Border with no name, so you need to find it by yourself. In the example below, I'm using the CommunityToolkit.WinUI.Extensions NuGet package.
private void MemberListView_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (sender is not ListView listView ||
listView.ContainerFromItem(listView.SelectedItem) is not ListViewItem selectedListViewItem ||
selectedListViewItem.FindDescendant<ListViewItemPresenter>() is not { } selectedListViewItemPresenter ||
selectedListViewItemPresenter.FindDescendants().OfType<Border>().LastOrDefault() is not Border selectionIndicator)
{
return;
}
selectionIndicator.Width = 64;
selectionIndicator.Height = 3;
selectionIndicator.Margin = new Thickness(0, 0, 0, -8);
selectionIndicator.HorizontalAlignment = HorizontalAlignment.Center;
selectionIndicator.VerticalAlignment = VerticalAlignment.Bottom;
}
1 Comment
Perhaps you should use a GridView instead? Set the Orientation to Vertical and the MaximumRowsOrColumns to 1 (weird name, but since it is vertical you can have multiple columns).
This will allow you to scroll horizontally using the mouse scrollwheel and change the selected item using the left/right keys or clicking.
<GridView x:Name="HorizontalList"
ItemsSource="{x:Bind MyList, Mode=OneWay}"
ScrollViewer.HorizontalScrollMode="Enabled"
ScrollViewer.HorizontalScrollBarVisibility="Visible"
ScrollViewer.VerticalScrollMode="Disabled"
ScrollViewer.VerticalScrollBarVisibility="Hidden">
<GridView.ItemsPanel>
<ItemsPanelTemplate>
<ItemsWrapGrid Orientation="Vertical"
MaximumRowsOrColumns="1"
ItemWidth="150"
ItemHeight="150" />
</ItemsPanelTemplate>
</GridView.ItemsPanel>
</GridView>
Comments
Consider using the SelectorBar control. It already has logic for selection indicator that could be restyled and repositioned. The SelectorBar is typically meant for navigation, but it could work for this purpose as a collection control instead. Unfortunately, it does not support data virtualization or an ItemsSource property, which could be limiting depending on your use case. I suggest using with a relatively known/small quantity of items.
You can see a working example in the WinUI 3 gallery app: https://apps.microsoft.com/detail/9P3JFPWWDZRC?hl=en-us&gl=US&ocid=pdpshare
Here is a link to the default style for SelectorBar on GitHub: https://github.com/microsoft/microsoft-ui-xaml/blob/main/src/controls/dev/SelectorBar/SelectorBar.xaml
API Reference: https://learn.microsoft.com/en-us/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.selectorbar
Design docs: https://learn.microsoft.com/en-us/windows/apps/design/controls/selector-bar

ControlTemplateof theListViewItem. You can modify properties on theListViewItemPresenterto control the selection check box, item positioning, and brush colors for visual states.