locked
ListView ScrollIntoView problem with StackPanel items on first view

    Question

  • I have three single-selection ListView controls in my app. They're in separate PopUp controls and are displayed by clicking on AppBar buttons. At startup, I initialize the CVS data then set the selected index for each ListView.

    One of the Listviews doesn't handle ScrollIntoView properly the first time it is displayed. The list is always shown with the first item at the top. The correct item is selected but is off screen. If I simply click the AppBar button to show the ListView again, the selected item is visible. ScrollIntoView works the second and subsequent times.

    The only major difference between the ListView that doesn't work properly and the others is that its ItemTemplate is a StackPanel (the others are just TextBlocks). My code that displays the PopUp is simple:

    listView->ScrollIntoView( listView->SelectedItem ); popUp->IsOpened = true;

    My guess is that the StackPanel ListView doesn't calculate its item heights prior to being shown, which means it doesn't know how to scroll the item into view. I have tried:

    1. ListView->UpdateLayout()

    2. Explicitly setting the Height of the item StackPanel in XAML

    Is there some way to force the ListView control to layout its items so that ScrollIntoView will work properly at startup?

    Edit: I tried replacing the StackPanel with a simple TextBlock (like the other ListViews) and it still didn't work. I wonder if the number of items makes a difference. The ListView that doesn't work has around 200 items in it while the ones that work properly only have 20-30 items.

    Edit2: I've confirmed that ListView->SelectedItem is valid on the first call to ScrollIntoView. Also, the ListView is in a Grid and has a fixed size, so there isn't any issue of the ListView's size being unknown at the time ScrollIntoView is called.


    • Edited by henador Friday, September 14, 2012 9:23 PM
    Friday, September 14, 2012 5:49 PM

Answers

  • So the twist in this scenario was this was a DirectX/XAML solution where SwapChainBackgroundPanel is involved vs. a pure XAML app which is what I had tested earlier. There is certainly some different behavior in this situation. I could not find an acceptable event to directly call ScrollIntoView from, so instead resorted to creating a Windows::UI::Xaml::DispatcherTimer in the Opened event with enough of an interval to allow time for the XAML document rendering to be completed. See if this approach works in your scenario.

    DirectXPage.xaml

    <Popup IsOpen="False" x:Name="PopUp_SelectProduct1"  Width="210" Height="562" Opened="PopUp_SelectProduct1_Opened">

    DirectXPage.xaml.cpp

     Windows::UI::Xaml::DispatcherTimer^ m_dispatcherTimer;	
    
    void DirectXPage::PopUp_SelectProduct1_Opened( Platform::Object^ sender, Platform::Object^ args )
     {
    	    // Set up a DispatchTimer
    	    TimeSpan span;
    		span.Duration = 50000000; //50ms
            m_dispatcherTimer = ref new DispatcherTimer();
            m_dispatcherTimer->Tick += ref new Windows::Foundation::EventHandler<Object^>(this, &Direct2DApp1::DirectXPage::ScrollPopup);
    		m_dispatcherTimer->Start();
     }
    void Direct2DApp1::DirectXPage::ScrollPopup(Platform::Object^ sender, Platform::Object^ e)
    {
    	m_dispatcherTimer->Stop();
    	ProductListView1->ScrollIntoView( ProductListView1->SelectedItem );
    	OutputDebugStringA("Scrolled\n");
    }

    Thanks!


    David Lamb



    Friday, September 21, 2012 12:07 AM
    Moderator

All replies

  • ScrollIntoView will not work until the layout has occurred, so adding it to the popup event handler 'Opened' achieves the result your after in my simple testing.

            <Popup Name="p1" Opened="p1_Opened_1">
                    <ListView Name="l1" HorizontalAlignment="Left" Height="240" VerticalAlignment="Top" Width="400" />
            </Popup>


    void LVScrollIntoView::MainPage::p1_Opened_1(Platform::Object^ sender, Platform::Object^ e) {

    l1->ScrollIntoView(l1->Items->GetAt(30)); }

    See if that will work for your scenario.

    David


    Monday, September 17, 2012 11:19 PM
    Moderator
  • Thanks for the suggestion, David. Unfortunately, it didn't work and I subsequently discovered that *none* of my ListViews actually scroll into view properly on first display (in my previous testing, the pre-selected items in those LV were always close enough to the top of the list that they were visible).

    I have a ton of work left to get my app's real functionality going (downloading and processing real-time data) that I can't waste any more time on a relatively minor UI issue like this. If I can't fix this later on before release and my users complain, which they will, I'll weasel-word my way out of it.

    Tuesday, September 18, 2012 2:30 PM
  • If you can email me a sample project exhibiting this behavior, I'll see if I can get it working for you. The snippet I pasted works in my project, but there may be some subtle differences between our projects.

    DavidLam AT Microsoft DOT com.

    Thanks!


    David Lamb

    Tuesday, September 18, 2012 4:47 PM
    Moderator
  • If you can email me a sample project exhibiting this behavior, I'll see if I can get it working for you. The snippet I pasted works in my project, but there may be some subtle differences between our projects.

    DavidLam AT Microsoft DOT com.

    Thanks!


    David Lamb

    I emailed you a .zipped example last night. Let me know if you didn't get it (I sent it to "davidlam", not "davidlamb" at msft).

    Thanks for the help.

    Wednesday, September 19, 2012 1:34 PM
  • So the twist in this scenario was this was a DirectX/XAML solution where SwapChainBackgroundPanel is involved vs. a pure XAML app which is what I had tested earlier. There is certainly some different behavior in this situation. I could not find an acceptable event to directly call ScrollIntoView from, so instead resorted to creating a Windows::UI::Xaml::DispatcherTimer in the Opened event with enough of an interval to allow time for the XAML document rendering to be completed. See if this approach works in your scenario.

    DirectXPage.xaml

    <Popup IsOpen="False" x:Name="PopUp_SelectProduct1"  Width="210" Height="562" Opened="PopUp_SelectProduct1_Opened">

    DirectXPage.xaml.cpp

     Windows::UI::Xaml::DispatcherTimer^ m_dispatcherTimer;	
    
    void DirectXPage::PopUp_SelectProduct1_Opened( Platform::Object^ sender, Platform::Object^ args )
     {
    	    // Set up a DispatchTimer
    	    TimeSpan span;
    		span.Duration = 50000000; //50ms
            m_dispatcherTimer = ref new DispatcherTimer();
            m_dispatcherTimer->Tick += ref new Windows::Foundation::EventHandler<Object^>(this, &Direct2DApp1::DirectXPage::ScrollPopup);
    		m_dispatcherTimer->Start();
     }
    void Direct2DApp1::DirectXPage::ScrollPopup(Platform::Object^ sender, Platform::Object^ e)
    {
    	m_dispatcherTimer->Stop();
    	ProductListView1->ScrollIntoView( ProductListView1->SelectedItem );
    	OutputDebugStringA("Scrolled\n");
    }

    Thanks!


    David Lamb



    Friday, September 21, 2012 12:07 AM
    Moderator
  • David,

    Thanks for the workaround. I'll give it a shot.

    Friday, September 21, 2012 4:27 AM