I love C#, XAML and Blend. It is very powerful and lets me create powerful solutions. As a example of it's power I will demonstrate my ScrollSelectedItemIntoViewBehavior. It will let you scroll to a selected item into view of a ListView or GridView without having to write any code.

Demo

The following video (GIF) shows you how you can use it to scroll to the selected product into view of a ListView. This can be done animated or instant.

My Solution

My solution is a Behavior which you can apply on any ListView or GridView using Blend for Visual Studio. I have included the Microsoft.Xaml.Behaviors.Uwp.Managed NuGet package to the project. The ScrollSelectedItemIntoViewBehavior class derives from the Behavior<T> class (from the NuGet package) in which T is a ListViewBase. This allows me to use (drop) the behavior on a ListView or GridView. In the OnAttached() and OnDetached() methods I subscribe/unsubscribe to the SelectionChanged event of the AssociatedObject, the ListView or GridView. In the AssociatedObject_SelectionChanged() method the AssociatedObject scrolls to the selected item. For the scrolling I use some code (extension methods) I found on StackOverflow which does the hard work. I only changed some naming of the methods to follow my own code conventions.

public class ScrollSelectedItemIntoViewBehavior : Behavior<ListViewBase> { protected override void OnAttached() { AssociatedObject.SelectionChanged += AssociatedObject_SelectionChanged; base.OnAttached(); } protected override void OnDetaching() { AssociatedObject.SelectionChanged -= AssociatedObject_SelectionChanged; base.OnDetaching(); } private async void AssociatedObject_SelectionChanged(object sender, SelectionChangedEventArgs e) { var item = e.AddedItems.FirstOrDefault(); if (item != null) { if (IsScrollAnimated) { await this.AssociatedObject.ScrollToItemAsync(item); } else { await this.AssociatedObject.ScrollIntoViewAsync(item); } } } /// <summary> /// Get or Sets the IsScrollAnimated dependency property. /// </summary> public bool IsScrollAnimated { get { return (bool)GetValue(IsScrollAnimatedProperty); } set { SetValue(IsScrollAnimatedProperty, value); } } /// <summary> /// Identifies the IsScrollAnimated dependency property. /// This enables animation, styling, binding, etc... /// </summary> public static readonly DependencyProperty IsScrollAnimatedProperty = DependencyProperty.Register(nameof(IsScrollAnimated), typeof(bool), typeof(ScrollSelectedItemIntoViewBehavior), new PropertyMetadata(true)); }

Using the Behavior

My sample project also contains some SampleData (products) which I used to populate a ListView. I have dragged the ScrollSelectedItemIntoViewBehavior from the Assets panel and dropped it on the ListView. The behavior also contains an IsScrollAnimated dependency property. The ToggleSwitch is databound to this property.

<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:App47" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:Interactivity="using:Microsoft.Xaml.Interactivity" xmlns:Behaviors="using:App47.Behaviors" x:Class="App47.MainPage" mc:Ignorable="d"> <Page.Resources> <DataTemplate x:Key="ProductTemplate"> <Grid Height="80" Margin="0,4"> <Grid.ColumnDefinitions> <ColumnDefinition Width="Auto" /> <ColumnDefinition Width="*" /> </Grid.ColumnDefinitions> <Image Source="{Binding ImageUrl}" Height="80" Width="80" /> <StackPanel Grid.Column="1" Margin="8,0,0,0"> <TextBlock Text="{Binding Name}" Style="{StaticResource TitleTextBlockStyle}" /> <TextBlock Text="{Binding Price}" Style="{StaticResource CaptionTextBlockStyle}" TextWrapping="NoWrap" /> </StackPanel> </Grid> </DataTemplate> </Page.Resources> <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" DataContext="{Binding Source={StaticResource SampleDataSource}}"> <Grid.ColumnDefinitions> <ColumnDefinition Width="380*" /> <ColumnDefinition Width="1541*" /> </Grid.ColumnDefinitions> <StackPanel> <Button Content="First" Click="ButtonFirst_Click" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="4" /> <Button Content="Middle" Click="ButtonMiddle_Click" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="4" /> <Button Content="Last" Click="ButtonLast_Click" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="4" /> <ToggleSwitch Header="IsAnimated" Margin="4" IsOn="{x:Bind myBehavior.IsScrollAnimated, Mode=TwoWay}" /> </StackPanel> <ListView x:Name="listViewProducts" Grid.Column="1" ItemTemplate="{StaticResource ProductTemplate}" ItemsSource="{Binding Products}"> <Interactivity:Interaction.Behaviors> <Behaviors:ScrollSelectedItemIntoViewBehavior x:Name="myBehavior" /> </Interactivity:Interaction.Behaviors> </ListView> </Grid> </Page>

The buttons click eventhandlers only set the SelectedIndex of the ListView. An MVVM solution in which the SelectedIndex is databound to a property of a model would also work.

public sealed partial class MainPage : Page { public MainPage() { this.InitializeComponent(); } private void ButtonFirst_Click(object sender, RoutedEventArgs e) { listViewProducts.SelectedIndex = 0; } private void ButtonMiddle_Click(object sender, RoutedEventArgs e) { listViewProducts.SelectedIndex = (listViewProducts.Items.Count - 1) / 2; } private void ButtonLast_Click(object sender, RoutedEventArgs e) { listViewProducts.SelectedIndex = listViewProducts.Items.Count - 1; } }

The code

I have published my code on GitHub. I hope you like it.

Fons