我有一个ListBox
,必须自动滚动到底部。在我的应用程序中,我必须检测用户是否已经看到某些项目,并且如果是这样的话,还要执行一些业务逻辑。我在这里使用虚拟化,只有当它可见时才调用item(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
。
所以问题是:有没有什么方法可以滚动到底部而不首先渲染它的顶部?
答案 0 :(得分:1)
我已将您附加的命令复制为
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>
我还在其中为ViewModel
添加了Load事件的绑定 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
处理程序
ViewModel中只有LoadCommand
,而ScrollIntoView
的AssociatedObject_SelectionChanged
醇>
所以基本上我建议做一些事情:
ScrollIntoView
处理程序中添加(另一个)Loaded
(对于集合的最后一项)
代码隐藏IsLoaded
以排除任何瞬态效果答案 1 :(得分:-1)
为什么不在设置DataContext或ItemSource后直接滚动到集合中的最后一个值?在设置数据上下文之前,不会呈现任何数据,直到退出构造函数为止。据我所知,如果你在构造函数中按顺序执行以下步骤,它应该按预期工作。
listBox.DataContext = _items;
listBox.ScrollIntoView(_items.Last());