I have an issue with WPF ListBox in TabControl. ListBox resets it's scrollbar position to 0 when I change tabs. Here is repro code:
<TabControl x:Name="_tabs">
<TabItem Header="1">
<ListBox ItemsSource="{Binding}" ScrollViewer.VerticalScrollBarVisibility="Auto"/>
</TabItem>
<TabItem Header="2">
<ListBox ItemsSource="{Binding}" ScrollViewer.VerticalScrollBarVisibility="Auto"/>
</TabItem>
</TabControl>
_tabs.DataContext = Enumerable.Range(1, 300).ToArray();
When the window opens I open the second tab, scroll list somewhere to the middle, return to the first tab and then open the second again. For some reason the list is scrolled to the top.
Why this happens? Have I made some stupid mistake?
The default behavior of WPF is to unload items which are not visible, which includes unloading TabItems which are not visible. This means when you go back to the tab, the TabItem gets re-loaded, and anything not bound (such as a scroll position) will get reset.
There
wasis a good site here which contains code to extend the TabControl and stop it from destroying it's TabItems when switching tabs, however the site appears to be down atm.Here's the code I use. It initially was from that site, although I've made some changes to it. It preserves the
ContentPresenter
of TabItems when switching tabs, and uses it to redraw the TabItem when you go back to the page. It takes up a bit more memory, however I find it better on performance since the TabItem no longer has to re-create all the controls that were on it.The TabControl template I usually use looks something like this:
Great answer! Cheers Rachel! I can't comment on existing posts so have added my own answer.
I found the above managed to solve the problem. However I also found it necessary to add:
to get the initial selected tab to load correctly - the ItemContainerGenerator had no contents and so GetSelectedTabItem failed to return a TabItem. Presumably this is something to do with rendering which has yet to happen when the template is applied.
I found this problem manifested itself only when binding the ItemsSource and SelectedItem of a tab control - in an application I am working on we have recently switched to using this so we could programmatically switch tabs to do a bit of custom navigation.
The Tab Item contents were originally specified by hand eg:
With that setup changing the selected item was fine (didn't reload tabs on selection) although it was only ever done by wpf. This seems to suggest that this behaviour can be turned off in the default control but only when not binding to a list of items (although I didn't confirm this to be the case).
Another solutions I attempted were changing the ItemSource binding Mode to OneTime but this did not solve the problem (we aren't using an INotifyCollectionChanged collection here anyway).