I have an IList
of viewmodels which are bound to a TabControl
. This IList
will not change over the lifetime of the TabControl
.
<TabControl ItemsSource="{Binding Tabs}" SelectedIndex="0" >
<TabControl.ItemContainerStyle>
<Style TargetType="TabItem">
<Setter Property="Content" Value="{Binding}" />
</Style>
</TabControl.ItemContainerStyle>
</TabControl>
Each viewmodel has a DataTemplate
which is specified in a ResourceDictionary
.
<DataTemplate TargetType={x:Type vm:MyViewModel}>
<v:MyView/>
</DataTemplate>
Each of the views specified in the DataTemplate are resource intensive enough to create that I would rather create each view just once, but when I switch tabs, the constructor for the relevant view is called. From what I have read, this is the expected behavior for the TabControl
, but it is not clear to me what the mechanism is which calls the constructor.
I have taken a look at a similar question which uses UserControl
s but the solution offered there would require me to bind to views which is undesirable.
This existing solution by @Dennis (with additional notes by @Gravitas) works very well.
However, there is another solution which is more modular and MVVM friendly as it uses an attached behaviour to achieve the same result.
See Code Project: WPF TabControl: Turning Off Tab Virtualization. As the author is technical lead at Reuters, the code is probably solid.
The demo code is really well put together, it shows a regular TabControl, alongside the one with the attached behavior.
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:
TabControlEx.cs
This goes into the same class as pointed to by the DataContext.
XAML
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.
Custom Tab
Alter the tab to use our new custom C# class, and point it at our new custom style using the
Style
tag: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 theCacheAllTabs
option to get the same effect (this switches off tab virtualization):For the record, I am not affiliated with DevExpress, I'm sure that Telerik has the equivalent.
Please check my answer from this post in SO. Hope it would solve the problem, but it is a bit off the MVVM road. Link
By default, the
TabControl
shares a panel to render it's content. To do what you want (and many other WPF developers), you need to extendTabControl
like so:TabControlEx.cs
XAML
Note: I did not come up with this solution. It has been shared in programming forums for several years and believe that it is in now one of those WPF recipes books. The oldest or original source for I believe was PluralSight .NET blog post and this answer on StackOverflow.
HTH,