我已经实现了一个运行良好的虚拟化面板,该面板实现了 IScrollInfo。我正在使用键盘让它工作。Panel 在 ListView 中用作 ListView.ItemsPanel。当用户按下所选项目正确更改但不滚动时,当您到达最后一个可见项目时,您不能再按下。我试图弄清楚如何让面板知道所选项目并适当地滚动。我尝试过四处搜索,但似乎找不到与我想做的事情相关的任何事情。一个正确方向的点将不胜感激。
编辑:这是 VirtualizingWrapPanel 的代码
我已经实现了一个运行良好的虚拟化面板,该面板实现了 IScrollInfo。我正在使用键盘让它工作。Panel 在 ListView 中用作 ListView.ItemsPanel。当用户按下所选项目正确更改但不滚动时,当您到达最后一个可见项目时,您不能再按下。我试图弄清楚如何让面板知道所选项目并适当地滚动。我尝试过四处搜索,但似乎找不到与我想做的事情相关的任何事情。一个正确方向的点将不胜感激。
编辑:这是 VirtualizingWrapPanel 的代码
所以我找到了一个效果很好的解决方案,我不确定它是否是最好的方法,但它似乎工作正常。
在遍历子项时的 ArrangeOverride 方法中,我执行以下操作。
var listViewItem = child as ListViewItem;
if (listViewItem != null)
{
listViewItem.Selected -= ListViewItemSelected;
listViewItem.Selected += ListViewItemSelected;
}
在 MeasureOverride 中,我在这里调用 CleanUpItems,我们需要取消订阅所选事件。
var listViewItem = children[i] as ListViewItem;
if (listViewItem != null)
{
listViewItem.Selected -= ListViewItemSelected;
}
我还添加了以下三个功能。
private void ListViewItemSelected(object sender, RoutedEventArgs e)
{
var listViewItem = sender as ListViewItem;
if(listViewItem == null) return;
var content = listViewItem.Content as CollectionViewGroup;
if(content != null) return; //item is a group header dont click
var items = ItemContainerGenerator as ItemContainerGenerator;
if(items == null) return;
BringIndexIntoView(items.IndexFromContainer(listViewItem));
listViewItem.Focus();
}
protected override void BringIndexIntoView(int index)
{
var offset = GetOffsetForFirstVisibleIndex(index);
SetVerticalOffset(offset.Height);
}
private Size GetOffsetForFirstVisibleIndex(int index)
{
int childrenPerRow = CalculateChildrenPerRow(_extent);
var actualYOffset = ((index / childrenPerRow) * ChildDimension.Height) - ((ViewportHeight - ChildDimension.Height) / 2);
if (actualYOffset < 0)
{
actualYOffset = 0;
}
Size offset = new Size(_offset.X, actualYOffset);
return offset;
}
GetOffsetForFirstVisibleIndex 函数可能会根据您的实现而有所不同,但如果其他人在想出解决方案时遇到问题,这应该是足够的信息。