将未实现的 ListViewItem 引入视图
Bring non-realised ListViewItem into view
我有一个开始时是空的 ListView。然后我不断地向 ListView 添加项目。在某些时候,所有项目都填满了整个可用空间,我想从那里将 ListView 滚动到刚刚添加的项目。
一般来说,这可以通过调用 ListViewItem.BringIntoView
或 ListView.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);
}
}
我有一个开始时是空的 ListView。然后我不断地向 ListView 添加项目。在某些时候,所有项目都填满了整个可用空间,我想从那里将 ListView 滚动到刚刚添加的项目。
一般来说,这可以通过调用 ListViewItem.BringIntoView
或 ListView.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);
}
}