列表框滚动查看器-默认滚动到底部
本文关键字:滚动 默认 底部 列表 | 更新日期: 2023-09-27 18:03:32
我有一个必须自动滚动到底部的ListBox
。在我的应用程序中,我必须检测某些项是否已经对用户可见,并在可见的情况下执行一些业务逻辑。我在这里使用虚拟化,它只在项目(vm)可见时才调用项目(vm)属性。
对于自动滚动,我使用的是完美的listbox.ScrollIntoView(listbox.SelectedItem);
,问题是ScrollIntoView
只会在ListBox
已经加载和渲染后运行,这意味着它首先从开始显示一些项目,之后它将滚动到底部…这对我来说是不可取的。我只是想立即滚动到底部(在ListBox
渲染之前)。
protected override void OnAttached()
{
base.OnAttached();
this.AssociatedObject.SelectionChanged += AssociatedObject_SelectionChanged;
}
void AssociatedObject_SelectionChanged(object sender, EventArgs e)
{
if (sender is ListBox)
{
ListBox listbox = (sender as ListBox);
if (listbox.SelectedItem != null)
{
listbox.Dispatcher.BeginInvoke((Action)(() =>
{
listbox.UpdateLayout();
if (listbox.SelectedItem != null)
{
listbox.ScrollIntoView(listbox.SelectedItem);
}
}));
}
}
}
protected override void OnDetaching()
{
base.OnDetaching();
this.AssociatedObject.SelectionChanged -= AssociatedObject_SelectionChanged;
}
我的ListBox
被设置为IsSynchronizedWithCurrentItem="True"
,它的ItemsSource
被绑定到ICollectionView
,我使用MoveCurrentToLast
。
所以问题是:有没有办法滚动到底部而不首先渲染它的顶部?
我将您附加的命令复制为
public class MyBehavior : Behavior<ListBox>
{
到一个XAML
<ListBox SelectedItem="SelCust" Name="MyListBox" Loaded="MyListBox_Loaded" IsSynchronizedWithCurrentItem="True" DisplayMemberPath="Name" ItemsSource="{Binding Customers}">
<i:Interaction.Behaviors>
<local:MyBehavior/>
</i:Interaction.Behaviors>
<i:Interaction.Triggers>
<i:EventTrigger EventName="Loaded">
<i:InvokeCommandAction Command="{Binding Path=LoadCommand}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</ListBox>
,我还添加了一个绑定的Load事件到ViewModel
public CustomerViewModel()
{
IList<Customer> customers = Customer.GetCustomers().ToList();
_customerView = CollectionViewSource.GetDefaultView(customers);
_customerView.MoveCurrentToLast();
_customerView.CurrentChanged += CustomerSelectionChanged;
}
private void CustomerSelectionChanged(object sender, EventArgs e)
{
// React to the changed selection
Debug.WriteLine("Here");
var sel = (sender as CollectionView).CurrentItem;
if ( sel!= null)
{
//Do Something
}
}
private DelegateCommand loadCommand;
public ICommand LoadCommand
{
get
{
if (loadCommand == null)
{
loadCommand = new DelegateCommand(VMLoad);
}
return (ICommand)loadCommand;
}
}
bool IsLoaded = false;
private void VMLoad(object obj)
{
IsLoaded = true;
}
和代码后面的
public MainWindow()
{
InitializeComponent();
DataContext = new CustomerViewModel();
}
private void MyListBox_Loaded(object sender, RoutedEventArgs e)
{
MyListBox.ScrollIntoView(MyListBox.Items[MyListBox.Items.Count - 1]);
}
当我调试它时,我看到这是触发的事件序列:
-
CurrentChanged
与最后一项的集合 -
Loaded
处理程序中的代码隐藏 -
LoadCommand
在ViewModel中,只有之后的 -
ScrollIntoView
fromAssociatedObject_SelectionChanged
所以基本上我的建议是:
- 的
- 对于任何你需要执行的动作,当你必须检测是否有些项目已经对用户可见时,首先检查
IsLoaded
以排除任何瞬态效应
Loaded
处理程序中添加(另一个)ScrollIntoView
(用于集合的最后一项)后台代码在设置了DataContext或ItemSource之后,为什么不简单地滚动到集合中的最后一个值?在设置数据上下文和退出构造函数之前,不会呈现任何数据。根据我的理解,如果你在构造函数中按顺序执行以下步骤,它应该像预期的那样工作。
listBox.DataContext = _items;
listBox.ScrollIntoView(_items.Last());