Xamarin中绑定ObservableRangeCollection的ListView如何在页面显示时自动向下滚动
Xamarin ListView 加载完成自动滚动到底部实现方案
前置修复:现有代码问题
你当前ViewModel的构造函数顺序存在逻辑错误,会触发空引用异常,需先初始化集合再调用数据刷新方法:
public NewFlashcardVM() { AddNewFlashcard = new ObservableRangeCollection<Flashcard>(); Refresh(); // 调整到集合初始化之后执行 }
方案1:后台代码快速实现
适合小型项目、无需严格遵循MVVM的场景,直接在页面对应的xaml.cs文件中重写OnAppearing方法:
protected override async void OnAppearing() { base.OnAppearing(); // 等待数据源加载完成 var vm = BindingContext as NewFlashcardVM; while(vm != null && vm.IsBusy) { await Task.Delay(50); } // 滚动到最后一项 if (ListAdd.ItemsSource is IList<Flashcard> dataList && dataList.Any()) { // 参数说明:滚动目标、滚动位置、是否开启动画 ListAdd.ScrollTo(dataList.Last(), ScrollToPosition.End, true); } }
方案2:Behavior 实现(MVVM友好)
适合严格遵循MVVM规范的项目,无需编写后台业务代码,复用性更高:
- 首先新建行为类
ListViewAutoScrollBehavior
using System.Collections.Specialized; using Xamarin.Forms; public class ListViewAutoScrollBehavior : Behavior<ListView> { protected override void OnAttachedTo(ListView bindable) { base.OnAttachedTo(bindable); bindable.PropertyChanged += OnListViewPropertyChanged; AttachCollectionChangeEvent(bindable.ItemsSource); } private void OnListViewPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) { if (e.PropertyName == nameof(ListView.ItemsSource) && sender is ListView lv) { AttachCollectionChangeEvent(lv.ItemsSource); } } private void AttachCollectionChangeEvent(object itemsSource) { if (itemsSource is INotifyCollectionChanged collection) { collection.CollectionChanged += OnCollectionChanged; // 首次加载已有数据直接滚动 if (itemsSource is IList { Count: > 0 } list) { AssociatedObject?.ScrollTo(list[^1], ScrollToPosition.End, true); } } } private void OnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) { if (sender is IList { Count: > 0 } list && AssociatedObject != null) { AssociatedObject.ScrollTo(list[^1], ScrollToPosition.End, true); } } protected override void OnDetachingFrom(ListView bindable) { base.OnDetachingFrom(bindable); bindable.PropertyChanged -= OnListViewPropertyChanged; if (bindable.ItemsSource is INotifyCollectionChanged collection) { collection.CollectionChanged -= OnCollectionChanged; } } }
- 在XAML中引入该行为即可
<ListView.Behaviors> <local:ListViewAutoScrollBehavior /> </ListView.Behaviors>
注意事项
- 需确认你使用的
ObservableRangeCollection的AddRange方法会触发CollectionChanged事件,部分老旧实现批量添加时不会发送通知,会导致滚动不触发,可以手动在AddRange执行后主动调用一次滚动逻辑。 - 若你在非UI线程触发滚动操作,需要套入
Device.BeginInvokeOnMainThread确保操作在UI线程执行。
内容的提问来源于stack exchange,提问作者Karlos18
相关产品推荐
相关产品推荐

