Question

I'm using a ListView to show Items in a List. The user can select the items himself, or use some 'preselect keys' to select items with specified attributes.

To check the items I use something like that:

for(int i;i<MyListView.Items.Count;++i)
{
    if( /*... Check if the items should be selected ...*/ )
        (MyListView.ItemContainerGenerator.ContainerFromIndex(i) as ListViewItem).IsSelected = true;
}

This works perfectly for items, that are visible at the time of excecution. But for items, that are not visible, ContainerFromIndex() returns null. I heard this has something to do with virtualization, and that the List doesn't know about items upside or downside the 'field of view'. But how comes that it is possible to have selected items in the List offside the 'field of view' when you select them manually?

And how to do a select of an item outside 'field of view'? I think that must be possible.

Thanks for any help, Marks

Was it helpful?

Solution

As you mentioned, my guess is that the problem is virtualization of the ListView items. By default, ListView (and ListBox) use VirtualizingStackPanel as their ItemsPanel to improve performance. A brief explanation for how it works can be read here.

You can substitute another Panel, however. In this case, try using a normal StackPanel. If you have a ton of items in the ListView, especially if they are complex items, performance might suffer a little.

<ListView>
    <ListView.ItemsPanel>
        <ItemsPanelTemplate>
            <StackPanel/>
        </ItemsPanelTemplate>
    </ListView.ItemsPanel>
</ListView>

Edit

You can also try to solution described at this similar question, depending on your model. However, this probably won't work for you.

OTHER TIPS

When dealing with virtualizing items controls, an alternative to disabling virtualization (which is in fact a useful feature at times, even if it interferes with correct operation of other parts of the API), is to find the VirtualizingPanel and tell it explicitly to scroll.

For example:

void ScrollToIndex(ListBox listBox, int index)
{
    VirtualizingPanel panel = FindVisualChild<VirtualizingPanel>(listBox);

    panel.BringIndexIntoViewPublic(index);
}

static T FindVisualChild<T>(DependencyObject o) where T : class
{
    T result = o as T;

    if (result != null)
    {
        return result;
    }

    int childCount = VisualTreeHelper.GetChildrenCount(o);

    for (int i = 0; i < childCount; i++)
    {
        result = FindVisualChild<T>(VisualTreeHelper.GetChild(o, i));

        if (result != null)
        {
            return result;
        }
    }

    return null;
}

I'm not very happy with the need to search through the visual tree to find the panel, but I'm not aware of any other way to get it, nor to scroll to a specific index when dealing with a virtualizing panel.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top