0

I've got a scrollable ListBox in a .xaml file that's bound to some data - an observable collection in a view model.

When new data is added to the collection, that data gets added to the top of the ListBox. When the ListBox contains lots of data and I scroll down the ListBox, new data gets added to the top of it however I can't see it unless I use the scrollbar to scroll to the top. How can I automatically scroll to the top after each new item is added to the observable collection?

WPF code:

        <ListBox Grid.Row="2"
                 Grid.Column="0"
                 ItemsSource="{Binding BagItems}"
                 ItemTemplateSelector="{StaticResource BagItemTemplateSelector}"
                 Grid.ColumnSpan="5"
                 Foreground="{DynamicResource DarkerGreyBrush}"
                 Background="{DynamicResource LightestGreyBrush}"
                 FontWeight="Medium"
                 HorizontalContentAlignment="Stretch"
                 ItemContainerStyle="{DynamicResource ListBoxContainerStyle}"
                 SelectedItem="{Binding SelectedItem}" 
                 ScrollViewer.HorizontalScrollBarVisibility="Disabled"
                 KeyDown="ListBox_KeyDown" ManipulationBoundaryFeedback="ListBox_ManipulationBoundaryFeedback">
            <i:Interaction.Behaviors>
                <behaviours:ListBoxSelectionModeOverrideBehaviour SupressKeyEvents="{Binding DialogController.DialogAvailable}" />
            </i:Interaction.Behaviors>
        </ListBox>

View model C# code:

if (shoppingBagItem != null)
{
    this.TryInvokeOnUiThread(() =>
    {
        this.BagItems.Insert(0, shoppingBagItem);
        this.SelectedItem = shoppingBagItem;
    });
}
Bhav
  • 1,957
  • 7
  • 33
  • 66

1 Answers1

1

The following Behavior class will automaticaly scroll the SelectedItem of a ListBox into view.

public class perListBoxHelper : Behavior<ListBox>
{
    protected override void OnAttached()
    {
        base.OnAttached();
        AssociatedObject.SelectionChanged += AssociatedObject_SelectionChanged;
    }

    protected override void OnDetaching()
    {
        base.OnDetaching();
        AssociatedObject.SelectionChanged -= AssociatedObject_SelectionChanged;
    }

    private static void AssociatedObject_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        var listBox = sender as ListBox;

        if (listBox == null)
        {
            return;
        }

        Action action = () =>
        {
            var selectedItem = listBox.SelectedItem;

            if (selectedItem != null)
            {                    
                listBox.ScrollIntoView(selectedItem);
            }
        };

        listBox.Dispatcher.BeginInvoke(action, DispatcherPriority.ContextIdle);
    }
}

Useage ...

<ListBox ... >
    <i:Interaction.Behaviors>
        <vhelp:perListBoxScrollSelecionIntoViewBehavior />
    </i:Interaction.Behaviors>
</ListBox>

More details on my blog post.

Peregrine
  • 4,287
  • 3
  • 17
  • 34