The answer by Dennis
is superb, and worked very nicely for me. However, the original article referred to in his post is now missing, so his answer needs a bit more information to be usable right out of the box.
This answer is given from an MVVM point of view, and was tested under VS 2013.
First, a bit of background. The way the first answer from Dennis
works is that it hides and shows the tab contents, instead of destroying and recreating said tab contents, every time the user switches a tab.
This has the following advantages:
- The contents of edit boxes do not disappear when the tab is switched.
- If you are using a Tree View in a tab, it does not collapse between tab changes.
- The current selection for any grids is retained between tab switches.
- This code is more agreeable with an MVVM style of programming.
- We do not have to write code to save and load the settings on a tab between tab changes.
- If you are using a 3rd party control (like Telerik or DevExpress), settings like the grid layout are retained between tab switches.
- Great performance improvements - the tab switching is virtually instant, as we are not redrawing everything every time a tab changes.
TabControlEx.cs
// Copy C# code from @Dennis's answer, and add the following property after the
// opening "<Style" tag (this sets the key for the style):
// x:Key="TabControlExStyle"
// Ensure that the namespace for this class is the same as your DataContext.
This goes into the same class as pointed to by the DataContext.
XAML
// Copy XAML from @Dennis's answer.
This is a style. It goes into the header of the XAML file. This style never changes, and is referred to by all tab controls.
Original Tab
Your original tab might look something like this. If you switch tabs, you will notice that the contents of the edit boxes will disappear, as the tab's contents are being dropped and recreated again.
<TabControl
behaviours:TabControlBehaviour.DoSetSelectedTab="True"
IsSynchronizedWithCurrentItem="True">
<TabItem Header="Tab 1">
<TextBox>Hello</TextBox>
</TabItem>
<TabItem Header="Tab 2" >
<TextBox>Hello 2</TextBox>
</TabItem>
Custom Tab
Alter the tab to use our new custom C# class, and point it at our new custom style using the Style
tag:
<sdm:TabControlEx
behaviours:TabControlBehaviour.DoSetSelectedTab="True"
IsSynchronizedWithCurrentItem="True"
Style="{StaticResource TabControlExStyle}">
<TabItem Header="Tab 1">
<TextBox>Hello</TextBox>
</TabItem>
<TabItem Header="Tab 2" >
<TextBox>Hello 2</TextBox>
</TabItem>
Now, when you switch tabs, you will find that the contents of the edit boxes are retained, which proves that everything is working nicely.
Update
This solution works very well. However, there is a more modular and MVVM friendly way to do this, which uses an attached behaviour to achieve the same result. See Code Project: WPF TabControl: Turning Off Tab Virtualization. I have added this as an additional answer.
Update
If you happen to be using DevExpress
, you can use the CacheAllTabs
option to get the same effect (this switches off tab virtualization):
<dx:DXTabControl TabContentCacheMode="CacheAllTabs">
<dx:DXTabItem Header="Tab 1" >
<TextBox>Hello</TextBox>
</dx:DXTabItem>
<dx:DXTabItem Header="Tab 2">
<TextBox>Hello 2</TextBox>
</dx:DXTabItem>
</dx:DXTabControl>
For the record, I am not affiliated with DevExpress, I'm sure that Telerik has the equivalent.
Update
Telerik does have the equivalent: IsContentPreserved
. Thanks to @Luishg in the comments below.
ItemsSource="{Binding Tabs, Mode=OneTime}"
? – SkiplaneIList
which doesn't notify ofPropertyChanged
I think this was effectively the case already. – IzabelItems
property which will be created only once. – KislevContentPresenters
for each tab which means I need to know how many tabs I'll need a priori. Although the tabs won't change when the Tabs are bound to theTabControl
, I will not know how many tabs will be there a priori. – Izabel