none
Scroll Listview to specific line

    Question

  • WPF, Browserlike app.
    I got one page containing a ListView.  I call a PageFunction. On return of the PageFunction, I add one line to the ListView, scroll the line into view, set focus on the line.

          ListViewItem item = ItemContainerGenerator.ContainerFromIndex(index) as ListViewItem;

          SelectedIndex = index;

          if (item != null)

          {

            ScrollIntoView(item);

            item.Focus();

          }


    This works. As long as the new line is in view the line gets the focus like it should.

    Problem is, things don't work when the line is not visible.
    If the line is not visible, there is no ListViewItem for the line generated, so ItemContainerGenerator.ContainerFromIndex returns null.

    But without the item, how do I scroll the line into view? I need the item to call ScrollIntoView().



    thanks,
    Sam


    • Edited by Sam Jost Friday, October 17, 2008 12:59 PM
    Friday, October 17, 2008 12:40 PM

Answers

  • would something like this work for you? Let me know if this helps.

    ScrollToAddedItem.xaml

    <Window x:Class="DUC.ScrollToAddedItem"

        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

        Title="ScrollToAddedItem" Height="500" Width="300">

        <StackPanel>

            <Button x:Name="btn" Content="AddNScroll" Margin="10" VerticalAlignment="Top" HorizontalAlignment="Center" Click="btn_Click"/>

            <ListView x:Name="lv" MaxHeight="250" MaxWidth="250" HorizontalAlignment="Center" />

        </StackPanel>

    </Window>


    ScrollToAddedItem.xaml.cs


    namespace DUC

    {

        /// <summary>

        /// Interaction logic for ScrollToAddedItem.xaml

        /// </summary>

        public partial class ScrollToAddedItem : Window

        {

            ObservableCollection<int> rows = new ObservableCollection<int>();

            Random rg = new Random();

            delegate void ScrollToLastItemDelegate();


            public ScrollToAddedItem()

            {

                InitializeComponent();

                InitItems();

                lv.ItemsSource = rows;

            }


            private void InitItems()

            {

                for (int i = 1; i < 100; i++)

                {

                    rows.Add(rg.Next(10000));

                }

            }


            private void btn_Click(object sender, RoutedEventArgs e)

            {

                rows.Add(rg.Next(10000));

                lv.Dispatcher.BeginInvoke(DispatcherPriority.Background,

                    new ScrollToLastItemDelegate(ScrollToLastItem));


            }


            public void ScrollToLastItem()

            {

                lv.SelectedItem = lv.Items.GetItemAt(rows.Count - 1);

                lv.ScrollIntoView(lv.SelectedItem);

                ListViewItem item = lv.ItemContainerGenerator.ContainerFromItem(lv.SelectedItem) as ListViewItem;

                item.Focus();

            }

        }

    }


    Evan Chua-Yap
    • Proposed as answer by Evan Chua-Yap Monday, October 20, 2008 8:10 PM
    • Marked as answer by Jim Zhou - MSFT Thursday, October 23, 2008 9:40 AM
    Monday, October 20, 2008 1:30 AM

All replies

  • Hi,

    Can you provide the full code of what you are trying to do.

    Thank You

    FEAR NOT TO BE JUST
    Friday, October 17, 2008 1:10 PM
  • I just found I phrased my question way too complicated. In reality it is much simpler.


    I got a WPF ListView.
    I want to scroll the last line into view.
    I can't use ScrollIntoView() since the last line is virtualised.

    So how do I scroll the last line into view then?
    Friday, October 17, 2008 1:23 PM
  • as a quick fix, disable UI Virtualization on the ListView. Then it would work. But if you have too many items in the listview, it would be darn slow.

    When virtualization is enabled, only visible elements woudl be loaded (so only they are inside the Visual Tree). So the list basically has no clue if there are any more items left. Disable it and try out.

    Associate Software Engineer http://krishnabhargav.blogspot.com
    Friday, October 17, 2008 1:28 PM
  • trueBuddi said:

    When virtualization is enabled, only visible elements woudl be loaded (so only they are inside the Visual Tree). So the list basically has no clue if there are any more items left. Disable it and try out.



    Is there any other way to scroll the ListView down to the bottom? I don't need to scroll using BringIntoView, some other way would be ok, too.
    Friday, October 17, 2008 1:32 PM
  • Try this:

    lv.ScrollIntoView(lv.Items[lv.Items.Count-1]);

    where "lv" is the name of the ListView control.

    By the way, I did not disable virtualization. Just did that on a virtualization-enabled listview.

    Associate Software Engineer http://krishnabhargav.blogspot.com
    Friday, October 17, 2008 1:41 PM
  • would something like this work for you? Let me know if this helps.

    ScrollToAddedItem.xaml

    <Window x:Class="DUC.ScrollToAddedItem"

        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

        Title="ScrollToAddedItem" Height="500" Width="300">

        <StackPanel>

            <Button x:Name="btn" Content="AddNScroll" Margin="10" VerticalAlignment="Top" HorizontalAlignment="Center" Click="btn_Click"/>

            <ListView x:Name="lv" MaxHeight="250" MaxWidth="250" HorizontalAlignment="Center" />

        </StackPanel>

    </Window>


    ScrollToAddedItem.xaml.cs


    namespace DUC

    {

        /// <summary>

        /// Interaction logic for ScrollToAddedItem.xaml

        /// </summary>

        public partial class ScrollToAddedItem : Window

        {

            ObservableCollection<int> rows = new ObservableCollection<int>();

            Random rg = new Random();

            delegate void ScrollToLastItemDelegate();


            public ScrollToAddedItem()

            {

                InitializeComponent();

                InitItems();

                lv.ItemsSource = rows;

            }


            private void InitItems()

            {

                for (int i = 1; i < 100; i++)

                {

                    rows.Add(rg.Next(10000));

                }

            }


            private void btn_Click(object sender, RoutedEventArgs e)

            {

                rows.Add(rg.Next(10000));

                lv.Dispatcher.BeginInvoke(DispatcherPriority.Background,

                    new ScrollToLastItemDelegate(ScrollToLastItem));


            }


            public void ScrollToLastItem()

            {

                lv.SelectedItem = lv.Items.GetItemAt(rows.Count - 1);

                lv.ScrollIntoView(lv.SelectedItem);

                ListViewItem item = lv.ItemContainerGenerator.ContainerFromItem(lv.SelectedItem) as ListViewItem;

                item.Focus();

            }

        }

    }


    Evan Chua-Yap
    • Proposed as answer by Evan Chua-Yap Monday, October 20, 2008 8:10 PM
    • Marked as answer by Jim Zhou - MSFT Thursday, October 23, 2008 9:40 AM
    Monday, October 20, 2008 1:30 AM
  • Yes, that does work!

    It seems the GetItemAt() is the main difference to my futile attempts.

    Thanks!
    Thursday, October 23, 2008 10:27 AM