비가시 ItemsControl
(ScrollViewer.CanContentScroll="False"
)에 대해 동일한 효과를 얻으려고 아래로 스크롤 한 다음 마우스로 표시된 컨테이너를 선택하면 가상화에 대한 효과가 나타납니다. 이것은 코드에서도 수행 할 수 있습니다.
CanContentScroll
을 false로 설정하면 가상화가 해제되어 모든 컨테이너가 항상 생성됩니다. 상단에 보이는 컨테이너를 얻으려면 ScrollViewer
의 VerticalOffset
에이를 때까지 컨테이너를 위에서부터 반복 할 수 있습니다. 일단 우리가 그것을 얻으면 우리는 단순히 BringIntoView
을 호출 할 수 있으며 가상화가 사용되는 것처럼 맨 위와 잘 정렬됩니다.
예
<ListBox ItemsSource="{Binding MyCollection}"
ScrollViewer.CanContentScroll="False"
ScrollViewer.ScrollChanged="listBox_ScrollChanged" >
이벤트 처리기에서 상위 볼 용기에 전화 BringIntoView
private void listBox_ScrollChanged(object sender, ScrollChangedEventArgs e)
{
ItemsControl itemsControl = sender as ItemsControl;
ScrollViewer scrollViewer = e.OriginalSource as ScrollViewer;
FrameworkElement lastElement = null;
foreach (object obj in itemsControl.Items)
{
FrameworkElement element = itemsControl.ItemContainerGenerator.ContainerFromItem(obj) as FrameworkElement;
double offset = element.TransformToAncestor(scrollViewer).Transform(new Point(0, 0)).Y + scrollViewer.VerticalOffset;
if (offset > e.VerticalOffset)
{
if (lastElement != null)
lastElement.BringIntoView();
break;
}
lastElement = element;
}
}
만이 PageDown
를 호출 할 때이 효과를 달성하기에 예를 들어 버튼을 클릭하면 확장 기능을 만들 수 있습니다. thod for ListBox
은 LogicalPageDown
입니다.
listBox.LogicalPageDown();
ListBoxExtensions
public static class ListBoxExtensions
{
public static void LogicalPageDown(this ListBox listBox)
{
ScrollViewer scrollViewer = VisualTreeHelpers.GetVisualChild<ScrollViewer>(listBox);
ScrollChangedEventHandler scrollChangedHandler = null;
scrollChangedHandler = (object sender2, ScrollChangedEventArgs e2) =>
{
scrollViewer.ScrollChanged -= scrollChangedHandler;
FrameworkElement lastElement = null;
foreach (object obj in listBox.Items)
{
FrameworkElement element = listBox.ItemContainerGenerator.ContainerFromItem(obj) as FrameworkElement;
double offset = element.TransformToAncestor(scrollViewer).Transform(new Point(0, 0)).Y + scrollViewer.VerticalOffset;
if (offset > scrollViewer.VerticalOffset)
{
if (lastElement != null)
lastElement.BringIntoView();
break;
}
lastElement = element;
}
};
scrollViewer.ScrollChanged += scrollChangedHandler;
scrollViewer.PageDown();
}
}
나는 이미 ScrollViewer
있어 귀하의 질문에 발견하지만, 다른 사람이이 질문에
public static T GetVisualChild<T>(DependencyObject parent) where T : Visual
{
T child = default(T);
int numVisuals = VisualTreeHelper.GetChildrenCount(parent);
for (int i = 0; i < numVisuals; i++)
{
Visual v = (Visual)VisualTreeHelper.GetChild(parent, i);
child = v as T;
if (child == null)
{
child = GetVisualChild<T>(v);
}
if (child != null)
{
break;
}
}
return child;
}
@Zmaster : 컨테이너의 상대 위치를 찾을 때 '여백'등이 포함될 수 있습니다. 그에 따라 내 답변을 업데이트했습니다 –
결국 모든 항목이 동일한 높이 (이것이 나의 경우)라는 가정하에 대상 오프셋을 계산하여 ScrollToOffset()을 사용하기로 결정했습니다. 아이템을 반복하는 것보다 효율적입니다. 반면에 귀하의 솔루션은 다른 항목의 높이에서 작동하므로 답변으로 받아 들였습니다. – Zmaster