0

I'd like to depopulate then repopulate later a ListBox while keeping the previous state of the ListBox ItemsSource (that's to say the current horizontal and vertical scroll offsets, and the selection).

Here's my code for the moment :

ObservableCollection<string> items = new ObservableCollection<string>();

public MainWindow() {
    InitializeComponent();

    for (int i = 1; i < 25; i++) items.Add("");

    listBox.ItemsSource = items;
}

private void btnDepopulate_Click(object sender, RoutedEventArgs e) {
    //how to backup the state?
    listBox.ItemsSource = null;
}

private void btnRepopulate_Click(object sender, RoutedEventArgs e) {
    listBox.ItemsSource = items;
    //how to restore the state?
}

With this code, when I repopulate the ListBox, the scroll properties and the selection are cleared.

Drarig29
  • 1,902
  • 1
  • 19
  • 42

1 Answers1

2

I would strongly recommend changing your listbox to Listview. Why?

Since ListView is inherited from ListBox you will have all features of ListBox in ListView Also.

For Windows 8.1 and above

Why would I recommed? Because ListView has ListViewPersistenceHelper Which will help you save and retrieve Relative Scroll position of ListView.

See this Example for how to implement ListViewPersistenceHelper

And for your selections, You can create a Global Variable in App.xaml.

public int ListViewScrollSelectedIndex;

which saves SelectedIndex of your ListView. When you repopulate your ListView, you can set it as

ListView.SelectedIndex  = ListViewScrollSelectedIndex;

This should take care of both issues.

For WPF

If you want to get the current scroll position of your List Box, You need to gain access to its scroll viewer first.

Here is the code that will fetch you the scroll viewer.

    private ScrollViewer GetObjectScrollViewer(DependencyObject dependencyObject)
    {
        if (dependencyObject is ScrollViewer)
            return dependencyObject as ScrollViewer;

        for (int i = 0; i < VisualTreeHelper.GetChildrenCount(dependencyObject); i++)
        {
            var _scrollViewer = GetObjectScrollViewer(VisualTreeHelper.GetChild(dependencyObject, i));
            if (_scrollViewer != null) return _scrollViewer;
        }
        return null;
    }

ScrollViewer has a VerticalOffset which will give you vertical position of Scrollviewer. Save it to a double in a variable created in App.xaml when you are depopulating the ListBox.

var _ListBoxScrollViewer = GetObjectScrollViewer(MyListBox);
ScrollPosition = _ListBoxScrollViewer.VerticalOffset;

Now when you populate it again assign the scrollviewer's ScrollToVerticalOffset so that it can go back to same position.

var _ListBoxScrollViewer = GetObjectScrollViewer(ListBox);
if (_ListBoxScrollViewer != null) _ListBoxScrollViewer.ScrollToVerticalOffset(ScrollPosition);

Hope This Helps.

Community
  • 1
  • 1
AVK
  • 3,893
  • 1
  • 22
  • 31