Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a simple way to have a ListView automatically scroll to the most recently added item without having to write any code in the code behind?

I have a ListView which is bound to an observable collection. As items are added to the observable collection, the listview does not automatically scroll to show the most recently added item. I am trying to adhere to good WPF practices and would like to avoid writing any code in the view's code-behind. Is there a simple way to accomplish this through the XAML or the corresponding Model's code?

<ListView HorizontalAlignment="Center" ItemsSource="{Binding ScenarioSnippets}" Background="{x:Null}" 
                      BorderBrush="{x:Null}" BorderThickness="0" SelectionMode="Single" VerticalAlignment="Top" 
                      HorizontalContentAlignment="Center" IsSynchronizedWithCurrentItem="True">
                <ListView.ItemContainerStyle>
                    <Style TargetType="{x:Type ListViewItem}">
                        <Setter Property="Focusable" Value="False" />
                    </Style>
                </ListView.ItemContainerStyle>
                <ListView.View>
                    <GridView Selector.IsSelected="True" AllowsColumnReorder="False">
                        <GridView.Columns>
                            <GridViewColumn CellTemplate="{StaticResource ScenarioSnippetItemCellTemplate}" 
                                            HeaderContainerStyle="{StaticResource GridViewHeaderStyle}" />
                        </GridView.Columns>
                    </GridView>
                </ListView.View>
        </ListView>
like image 626
skquesada Avatar asked Dec 12 '11 20:12

skquesada


2 Answers

You could use a Blend behavior:

public class AutoScrollToLastItemBehavior : Behavior<ListBox>
{
    protected override void OnAttached()
    {
        base.OnAttached();
        var collection = AssociatedObject.Items.SourceCollection as INotifyCollectionChanged;
        if (collection != null)
            collection.CollectionChanged += collection_CollectionChanged;
    }

    protected override void OnDetaching()
    {
        base.OnDetaching();
        var collection = AssociatedObject.Items.SourceCollection as INotifyCollectionChanged;
        if (collection != null)
            collection.CollectionChanged -= collection_CollectionChanged;
    }

    private void collection_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        if (e.Action == NotifyCollectionChangedAction.Add)
        {
            ScrollToLastItem();
        }
    }

    private void ScrollToLastItem()
    {
        int count = AssociatedObject.Items.Count;
        if (count > 0)
        {
            var last = AssociatedObject.Items[count - 1];
            AssociatedObject.ScrollIntoView(last);
        }
    }
}

XAML:

<ListView ItemsSource="...">
    <i:Interaction.Behaviors>
        <local:AutoScrollToLastItemBehavior />
    </i:Interaction.Behaviors>
</ListView>

(the Behavior and Interaction classes can be found in System.Windows.Interactivity.dll in the Blend SDK)

like image 142
Thomas Levesque Avatar answered Sep 30 '22 21:09

Thomas Levesque


You need to create an Attached Behavior which will allow your ListView to honor the MVVM paradigm which is what you are ultimately after.

A solution/example with ListBox (easily modified for a ListView) can be found here.

like image 26
Aaron McIver Avatar answered Sep 30 '22 22:09

Aaron McIver