将未实现的 ListViewItem 引入视图

Bring non-realised ListViewItem into view

我有一个开始时是空的 ListView。然后我不断地向 ListView 添加项目。在某些时候,所有项目都填满了整个可用空间,我想从那里将​​ ListView 滚动到刚刚添加的项目。

一般来说,这可以通过调用 ListViewItem.BringIntoViewListView.ScrollIntoView(ListViewItem) 来完成。

但是,ListView 绑定到 ListCollectionView,其源是 ViewModel 项的 ObservableCollection。因此,我将 ViewModel-items 添加到该集合中。然后通过绑定创建视图项。

由于该项目在可见区域之外,因此不会立即创建 ListViewItem,更不用说实现了。如果滚动视图靠近ListView的底部,ListViewItem将在不久后创建并实现。1
如果滚动视图在 ListView 的中间某处,它根本不起作用。

IsVirtualizing 设置为 false 将解决此问题,因为无论如何都会创建并实现该项目。但这显然有一些性能缺点。

因此,我正在尝试找到一种方法来创建和实现刚刚添加到集合中的项目,并最终可以将其带入视图。

有人知道如何解决这个问题吗?


1 如果滚动视图关闭到底部,它基本上可以工作,但有一个奇怪的行为,似乎只有所有其他 ListViewItem 都进入视图。

根据你的问题很难说出确切的问题。但是,这可能是因为 Equals 函数的行为。考虑这个结构:

<DockPanel>
    <Button Name="addItem" Click="addItem_Click" Content="Add new and scroll" DockPanel.Dock="Bottom"/>
    <ListView Name="sv" ScrollViewer.VerticalScrollBarVisibility="Visible">
    </ListView> 
</DockPanel>

有尝试添加新项目并滚动到末尾的按钮。

如果您添加不同的项目,它将起作用:

private void addItem_Click(object sender, RoutedEventArgs e)
{
    if (sv.ItemsSource == null)
        sv.ItemsSource = new ObservableCollection<string>();

    string newitem = "new item" + (sv.Items.Count + 1).ToString();
    ((ObservableCollection<string>)sv.ItemsSource).Add(newitem);
    sv.ScrollIntoView(newitem);
}

请注意,字符串永远不会相等(请参阅 (sv.Items.Count + 1).ToString() 部分)。但是,这不起作用:

private void addItem_Click(object sender, RoutedEventArgs e)
{
    if (sv.ItemsSource == null)
        sv.ItemsSource = new ObservableCollection<string>();

    string newitem = "new item";
    ((ObservableCollection<string>)sv.ItemsSource).Add(newitem);
    sv.ScrollIntoView(newitem);
} 

因为 Equals returns 第一项。

VirtualizationPanel 有一个方法 BringIndexIntoViewPublic 可以生成项目并使其可见。

这是一个包含所有相关代码的示例。

public class ListView_ViewModel
{
  private CollectionViewSource _collectionViewSource;
  private ObservableCollection<ListViewItem_ViewModel> _listViewItemViewModels;
  private ListView _listView;

  private void AddItem()
  {
    var newListViewItemViewModel = new ListViewItem_ViewModel();
    _listViewItemViewModels.Add(newListViewItemViewModel);
    var indexOfNewItem = _collectionViewSource.View.Cast<ListViewItem_ViewModel>()
                           .ToList().IndexOf(newListViewItemViewModel);
    var virtualizingPanel = VisualTreeHelper.FindChild<VirtualizingPanel>(_listView);
    virtualizingPanel.BringIndexIntoViewPublic(indexOfNewItem);
  }
}