microsoft / microsoft-ui-xaml

Windows UI Library: the latest Windows 10 native controls and Fluent styles for your applications
MIT License
6.36k stars 678 forks source link

Proposal: Add FirstVisibleIndex property in ListView #1847

Open mdmozibur opened 4 years ago

mdmozibur commented 4 years ago

This will be a nice addition in ListViewBase or ListView or ItemsControl to indicate which item is in the first row of visible items.

ranjeshj commented 4 years ago

If you are using ListView, the underlying panel is ItemsStackPanel. ItemsStackPanel provides First/Last-Visible/Cached Index properties. Same for GridView/ItemsWrapGrid. You can get to ItemsStackPanel from ListView using its ItemsPanelRoot property.

Just curious, what do you need the first visible index for ?

This would be a nice addition to have for ItemsRepeater where we can make it independent of the layout and have just one implementation for ItemsRepeater.

mdmozibur commented 4 years ago

@ranjeshj The ListView I am using has a lots of items ( > 500). I know that ListView uses data virtualization internally. Every now and then, it's SelectedItems get updated. I just clear the SelectdItems and then add the newly selected items using a for loop. Now, this seems to be a bottleneck in my app. So I have this idea that I will have a separate list of selected items and only add those items that are currently in view among them in listview.SelectedItems. I cant use SelectRange() because the items to be selected are not necessarily in order.

ranjeshj commented 4 years ago

Could you provide more details ? Are you saying that clearing and adding a bunch of selected items is causing a performance issue so you are going to manage your own selection state ? I believe ListView just tracks the selected index ranges. It also provides a way for you to track selection state using ISelectionInfo, If your ItemsSource implements this interface, ListView will call those methods whenever an item is selected/deselected and you can just flip a flag in your data object. This will avoid complex index tracking logic implemented otherwise in ListView to store the selection state. Hope that helps.

mdmozibur commented 4 years ago

To be clear : I have to manually select/deselect the items in the listview, for some certain need of my app. So I have this code:

listView.SelectedItems.Clear();

for (int i = 0; i < newSelectionItems.Count; i++)
{
    listView.SelectedItems.Add(newSelectionItems[i]);
}
listView.ScrollIntoView(newSelectionItems[0], ScrollIntoViewAlignment.Leading);

This is causing performance issue. The list view doesn't use an ItemsSource, it just adds / removes from Items

mdmozibur commented 4 years ago

So my idea is to avoid adding every element of newSelectionItems in listView.SelectedItems. I want to skip adding those items that aren't currently in view. And refresh the selection when the listview scrolls

ranjeshj commented 4 years ago

500 Items is a lot of UIElements for ListView to perform layout on. How are those items created? If you use ItemsSource/ItemTemplate instead I think it can drastically improve your performance since it will create UIElements only for the ones in view on demand.

StephenLPeters commented 4 years ago

@anawishnoff FYI, I'm not sure if the proposed API is the correct solution but lets make sure the issue isn't forgotten.

anawishnoff commented 4 years ago

I definitely like the idea of implementing this for ItemsRepeater, as it's already implemented in ItemsStackPanel/ItemsWrapGrid which are the "backbones" for ListView/GridView.

In this case, could you just use the FirstVisibleIndex property on the ListView's underlying ItemsPanelRoot property, then compare what's currently visible using the IndexFromContainer method for each selected ListViewItem? Although if the majority of items are getting selected, I predict that would negatively impact performance