locked
ContainerFromItem always returns null when used with a grouped ListView in a Windows 8.1 app

    Question

  • The following works fine when I pass in a ListView that is not grouped. It fails otherwise.

    private void ScrollSelectedItemIntoView(ScrollViewer scrollViewer, ListView listView) { ListViewItem selectedListItem = (ListViewItem)listView.ContainerFromItem(listView.SelectedItem); scrollViewer.UpdateLayout(); GeneralTransform offsetTransform = selectedListItem.TransformToVisual(listView); Point offset = offsetTransform.TransformPoint(new Point(0, 0)); scrollViewer.ChangeView(0, offset.Y, 1); }



    NFG

    Tuesday, October 14, 2014 6:39 AM

All replies

  • Can you define "works fine"?  What exactly doesn't work?  Telling us what the expected results are, and what actually happens will help.  Do you get an exception?  if so which line of code?

    Bret Bentzinger (MSFT) @awehellyeah

    Tuesday, October 14, 2014 10:37 PM
    Moderator
  • Hi Bret,

    selectedListItem is always null if the ListView is grouped, otherwise the scrolling works. Essentially all I want is to programmatically scroll to view a list tem. When I say the code works fine I mean I can scroll the item into view. But this only works if my ListView is flat. As soon as I use grouping I can't use the same code because of the null I explained above. My question is what do I have to change in my code for it to support grouping. It doesn't matter if the solution would be completely different from the one that works for flat lists, but I need to find out how to scroll programmatically with grouped lists. If you can help me I will be very grateful. Thanks. 


    NFG

    Wednesday, October 15, 2014 1:13 AM
  • I had a similar issue. Then, I realized that I needed to have the exact item in order to scroll to it in a list. In my case a solution was to query the item by ID and then use the ScrollIntoView method of the ListView:

    // MyViewModel is a type of your item.
    // MyViewModel must have an ID property serving as a primary key.
    // myCollection is the data source collection for your list.
    // selectedId is an ID of a selected item you want to scroll to.
    
    // Grab the selected item from the collection.
    MyViewModel selectedItem = myCollection.Where(it => it.ID == selectedId).FirstOrDefault();
    
    if (selectedItem != null)
    {
        await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () => 
        { 
            listView.UpdateLayout();
            listView.ScrollIntoView(selectedItem);
        });
    }
    Leszek

    My Apps



    • Edited by ata6502 Wednesday, October 15, 2014 3:02 AM
    Wednesday, October 15, 2014 2:56 AM
  • Thanks Leszek, I tried your suggestion but I am still stuck.

    I call ScrollSelectedItemIntoView in two places is my application. In one I pass a ListView that uses as its source a collection ItemsList that fits well with your code and if I write the same kind of code as yours to pick the SelectedItem it still works. So the code you provided is fine and I can use it with the first list view.

    But the second call to  ScrollSelectedItemIntoView gets another ListView that uses a CollectionViewSource with IsGrouping=true and has a GroupStyle template. The Source for that one is based on the same ItemsList but with a GroupBy:

    vm.ItemsList.GroupBy(i => i.Type).OrderBy(g => g.Key);

    Apart from the fact that the scroll doesn't work with this grouped ListView it displays as expected. So it is not that the xaml is wrong. Grouping is working fine. But again the ContainerFromItem API simply doesn't work in this case and my app is not scrolling when a grouped view is displayed.

    I can deliver the app as it is but it makes me feel sad that the scrolling feature is only available when the list is displayed flat. Is it impossible to programmatically scroll grouped listviews? If that's so we have a flaw in the APIs. 


    NFG

    Wednesday, October 15, 2014 5:27 AM
  • I used this sample:
    http://msdn.microsoft.com/en-us/library/windows/apps/xaml/hh780627.aspx

    I got rid of the grid view and added a button to execute the listView.ScrollIntoView() method.

    I added a listview selectionchanged handler and store the selected object.  In the UI I scroll down to item D in project2 and select it.

    Then I scrolled up and clicked the button.  It successfully scrolls that item into view.

    So there is not a problem with scrolling to an item in a listView that is grouped.   Are you sure you have what you think is the correct item?


    Bret Bentzinger (MSFT) @awehellyeah

    Wednesday, October 15, 2014 5:35 PM
    Moderator
  • Hi NFG,

    The key is to obtain the data item from the data source before the grouping is applied. Alternatively, you can keep the original data source (in the above code snippet it is myCollection) and do the grouping to another collection that you assign to a CollectionViewSource (which in turn is used to populate your GridView).

    Try this approach as a test and see how it works.

    Leszek


    My Apps


    • Edited by ata6502 Wednesday, October 15, 2014 6:00 PM
    Wednesday, October 15, 2014 5:59 PM
  • Hi Bret.

    Older issues (which I don't remember exactly) were the reason why I have my ListView inside a ScrollViewer and I am not using the ListView.ScrollIntoView but a method of the ScrollViewer to get the scrolling I need. It works as expected provided there is no grouping. Please refer to my private method ScrollSelectedItemIntoView. I would rather keep the logic of my solution as it is and figure out what is wrong with the code I have in the private method that receives one ScrollViewer and one ListView and scrolls to the selected item. Based on Leszek suggestion I am making some changes to make sure I have the selected item correctly assigned.

    vm.ItemsList is an ObservableCollection<ItemTitle> that is used by a ListView also called ItemsList. 

    ItemTitle item1 = vm.ItemsList.Where(i=>i .Id==selected.Id).FirstOrDefault();

    Originally I was just using "selected" which is assigned in the SelectionChanged event. I keep this item1 and only then I group the list

    groupItemsList.Source = vm.ItemsList.GroupBy(i=>i.Type).OrderBy(g=>g.Key);

    groupItemsList is the CollectionViewSource for the GroupedItemsList.

    Now in my private method I make sure I use this item1, so it seems I am using the correct item. But I still get the same null returning from listview.ContainerFromItem(item1).

    Let's narrow down all the discussion to just one simple question:

    Can I use the method ContainerFromItem of a ListView when the list view is grouped?


    NFG

    Wednesday, October 15, 2014 10:48 PM