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;
});
}
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.