WPF MVVM中PropertyChanged触发时滚动至已选中项的实现
解决WPF ListView已选中条目属性变更时的滚动问题
方案一:新增专用触发属性(推荐)
通过在ViewModel中添加一个专门用于触发滚动的属性,监听该属性变化执行滚动,不受条目原有选中状态影响:
- ViewModel中添加触发属性
// 替换YourItemType为你的列表项实体类型 private YourItemType _itemToScrollTo; public YourItemType ItemToScrollTo { get => _itemToScrollTo; set { if (_itemToScrollTo != value) { _itemToScrollTo = value; OnPropertyChanged(nameof(ItemToScrollTo)); } } }
- 属性变更时赋值触发滚动
在处理列表项属性变更的逻辑中,除了维持选中状态,同时给ItemToScrollTo赋值:
// changedItem为属性发生变更的列表项 var changedItem = ...; // 保持原有选中逻辑 ICollectionView view = CollectionViewSource.GetDefaultView(YourItemsCollection); view.MoveCurrentTo(changedItem); // 触发滚动的关键步骤 ItemToScrollTo = changedItem;
- 视图代码后置监听属性变化
在窗口/控件的Loaded事件中订阅ViewModel的PropertyChanged事件,当ItemToScrollTo变化时执行滚动:
private void YourView_Loaded(object sender, RoutedEventArgs e) { if (DataContext is YourViewModel vm) { vm.PropertyChanged += Vm_PropertyChanged; } } private void Vm_PropertyChanged(object sender, PropertyChangedEventArgs e) { var vm = sender as YourViewModel; if (e.PropertyName == nameof(YourViewModel.ItemToScrollTo) && vm?.ItemToScrollTo != null) { YourListView.ScrollIntoView(vm.ItemToScrollTo); } }
方案二:临时取消再重新选中(不推荐)
通过先取消选中目标条目,再重新选中的方式触发SelectionChanged事件,缺点是会导致选中状态短暂闪烁:
var changedItem = ...; ICollectionView view = CollectionViewSource.GetDefaultView(YourItemsCollection); // 先取消选中 view.MoveCurrentTo(null); // 延迟执行重新选中,避免UI响应不及时 Dispatcher.BeginInvoke(new Action(() => view.MoveCurrentTo(changedItem)));
方案三:使用自定义行为(MVVM友好)
如果想避免代码后置,可通过Blend Behaviors创建自定义行为,绑定ViewModel属性实现无代码后置的滚动触发:
- 创建ScrollToItemBehavior
public class ScrollToItemBehavior : Behavior<ListView> { public static readonly DependencyProperty ItemToScrollProperty = DependencyProperty.Register(nameof(ItemToScroll), typeof(object), typeof(ScrollToItemBehavior), new PropertyMetadata(null, OnItemToScrollChanged)); public object ItemToScroll { get => GetValue(ItemToScrollProperty); set => SetValue(ItemToScrollProperty, value); } private static void OnItemToScrollChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { var behavior = d as ScrollToItemBehavior; behavior?.AssociatedObject?.ScrollIntoView(e.NewValue); } }
- XAML中附加行为
<ListView x:Name="YourListView" ItemsSource="{Binding YourItemsView}"> <i:Interaction.Behaviors> <local:ScrollToItemBehavior ItemToScroll="{Binding ItemToScrollTo}" /> </i:Interaction.Behaviors> <!-- ListView其他内容 --> </ListView>
(需添加命名空间xmlns:i="http://schemas.microsoft.com/xaml/behaviors")
只要ViewModel的ItemToScrollTo属性变化,就会自动触发ListView滚动,完全符合MVVM模式。
内容的提问来源于stack exchange,提问作者KingGizzard237
相关产品推荐
相关产品推荐

