Get the first visible item in a WPF ListView C #

Does anyone know how to get a ListViewItem by capturing the first visible item in a ListView? I know how to get an element with index 0, but not the first visible one.

+5
source share
5 answers

It was so painful to work:

HitTestResult hitTest = VisualTreeHelper.HitTest(SoundListView, new Point(5, 5)); System.Windows.Controls.ListViewItem item = GetListViewItemFromEvent(null, hitTest.VisualHit) as System.Windows.Controls.ListViewItem; 

And the function to get the list item:

 System.Windows.Controls.ListViewItem GetListViewItemFromEvent(object sender, object originalSource) { DependencyObject depObj = originalSource as DependencyObject; if (depObj != null) { // go up the visual hierarchy until we find the list view item the click came from // the click might have been on the grid or column headers so we need to cater for this DependencyObject current = depObj; while (current != null && current != SoundListView) { System.Windows.Controls.ListViewItem ListViewItem = current as System.Windows.Controls.ListViewItem; if (ListViewItem != null) { return ListViewItem; } current = VisualTreeHelper.GetParent(current); } } return null; } 
+4
source

Trying to find something similar, I thought that I would share my result (as it seems easier than other answers):

A simple visibility test I got from here .

 private static bool IsUserVisible(FrameworkElement element, FrameworkElement container) { if (!element.IsVisible) return false; Rect bounds = element.TransformToAncestor(container).TransformBounds(new Rect(0.0, 0.0, element.ActualWidth, element.ActualHeight)); var rect = new Rect(0.0, 0.0, container.ActualWidth, container.ActualHeight); return rect.Contains(bounds.TopLeft) || rect.Contains(bounds.BottomRight); } 

You can then iterate over the listbox items and use this test to determine which ones are visible. Since listboxitems are always ordered, the first visible in this list will be the first visible to the user.

 private List<object> GetVisibleItemsFromListbox(ListBox listBox, FrameworkElement parentToTestVisibility) { var items = new List<object>(); foreach (var item in PhotosListBox.Items) { if (IsUserVisible((ListBoxItem)listBox.ItemContainerGenerator.ContainerFromItem(item), parentToTestVisibility)) { items.Add(item); } else if (items.Any()) { break; } } return items; } 
+3
source
+2
source

We only need to calculate the offset of our list, and the first visible element will be the element in the index equal to VerticalOffset ...

  // queue is the name of my listbox VirtualizingStackPanel panel = VisualTreeHelper.GetParent(queue.Items[0] as ListBoxItem) as VirtualizingStackPanel; int offset = (int)panel.VerticalOffset; // then our desired listboxitem is: ListBoxItem item = queue.Items[offset] as ListBoxItem; 

Hope this helps you.,.

+2
source

It seems that the versatility of WPF ListView does not allow the class to provide a property similar to TopItem WinForms. However, if the instance is configured with VirtualizingStackPanel , you can still query the superscript directly. This avoids the search and iteration required by other approaches. (The approach is based on this post .)

I think the hit test method used in the accepted answer is more general, but if you really need a list index, not a list item, this can save the IndexOf call.

My application needed to save and restore the position of the list after making significant changes to the contents of the list. The code for setting the top position (based on this post ) is also shown below. For convenience, they are implemented as extension methods.

 public static class ListViewExtensions { public static int GetTopItemIndex(this ListView lv) { if (lv.Items.Count == 0) { return -1; } VirtualizingStackPanel vsp = lv.GetVisualChild<VirtualizingStackPanel>(); if (vsp == null) { return -1; } return (int) vsp.VerticalOffset; } public static void ScrollToTopItem(this ListView lv, object item) { ScrollViewer sv = lv.GetVisualChild<ScrollViewer>(); sv.ScrollToBottom(); lv.ScrollIntoView(item); } } 

The extremely handy GetVisualChild method from the MSDN publication :

 public static class VisualHelper { public static T GetVisualChild<T>(this Visual referenceVisual) where T : Visual { Visual child = null; for (Int32 i = 0; i < VisualTreeHelper.GetChildrenCount(referenceVisual); i++) { child = VisualTreeHelper.GetChild(referenceVisual, i) as Visual; if (child != null && child is T) { break; } else if (child != null) { child = GetVisualChild<T>(child); if (child != null && child is T) { break; } } } return child as T; } } 

Note on using ScrollToTopItem : ScrollToBottom() takes effect immediately, but it seems that ScrollIntoView() postponed. So if you call GetTopItemIndex() right after ScrollToTopItem() , you get the index for the item at the bottom.

0
source

Source: https://habr.com/ru/post/1311164/


All Articles