Click here to Skip to main content
15,867,488 members
Articles / Desktop Programming / WPF

Persist the Visual Tree when switching tabs in the WPF TabControl (Optimized)

Rate me:
Please Sign up or sign in to vote.
4.83/5 (9 votes)
9 Apr 2012CPOL4 min read 50.3K   2.6K   15   16
This is an alternative for "Persist the Visual Tree when switching tabs in the WPF TabControl".

Introduction

Once upon a time I happened to work on a project which used TabControl to switch from one view to the next. All was well except it took forever to switch between views. Each view recreated the entire visual tree every time it became active. A quick search brought me to this excellent article by Jason Ching: Persist the Visual Tree when switching tabs in the WPF TabControl. It did precisely what I needed. I started to use his code and performance increased dramatically but there was still room for improvement. This article explains what could be done to already good code to make it even better.

Background

The idea behind Jason’s implementation in simple words could be described as this: Create behaviour, attach it to the TabControl where it waits for a new source items to be created (or whole new Items Source container attached). Once new item is created the behaviour creates a TabItem instance and wraps source item in it. This simple trick prevents TabControl from discarding TabItem’s instance and persists visual tree of the Tab.

Implementation

The behaviour is implemented by three classes: PersistTabBehavior, PersistTabItemsSourceHandler, and PersistTabSelectedItemHandler.

  • PersistTabBehavior – handles attached properties and maintains two static dictionaries where instances of Tab Controls are associated with Items Source and Selected Item handlers.
  • PersistTabSelectedItemHandler – translates internal TabControl selection into external selection.
  • PersistTabItemsSourceHandler – handles creating and manipulating TabItems associated with data source items.

For more details please consult original article.

Improvements

First thing I thought would improve performance is if we could get rid of the dictionaries and lookup process associated with them. Instead the instance of the behaviour should hold reference to both the TabControl as well as reference to items source.

I also thought that three different classes for one simple control behaviour is a bit of an overkill. If all the references are held in one place it is much easier to access only one instance of the object as opposed to multiple so I’ve merged all these classes into only one.

Referring external items source container is easy; we could simply store it in one of the fields.

The challenge is in making TabControl to reference correct instance of the handler which responds to changes in internal TabControl.SelectedItem property. TabControl.SelectedItem is an attached property of the TabControl class. So we could solve reference problem by using WPF Binding, after all Bindings where designed just for that purpose. Binding contains references to both the target property instance as well as reference to source instance. This allows us to retrieve correct instance just by examining the Binding object. This effectively eliminating a need for the dictionaries.

Now any time either TabItemGeneratorBehavior.SelectedItemProperty or TabItemGeneratorBehavior.ItemsSourceProperty is attached to the control we create instance of TabItemGeneratorBehavior and initialize fields _innerSelection, _tabControl, _itemsSource with references to respective objects, attach to required events and etc.

At the same time we create binding between TabControl.SelectedItem and TabItemGeneratorBehavior.SelectedTabItem public property of the behaviour:

C#
_tabControl = tab;
_tabControl.Loaded += OnTabLoaded;
_tabControl.SetBinding(TabControl.SelectedItemProperty,
                       new Binding("SelectedTabItem") { Source = this });

After that the behaviour operates exactly as the original.

Using the Code

I’ve provided a sample project to demonstrate behaviour's functionality.

The screen is split with two TabControls populating the area. The control on the left is not using the behaviour and control on the right does. The view area of the tab displays the unique ID of the TabItem instance that is associated with the active tab.

As you can see on the left, TabControl reuses same instance of the TabItem class to display all of the items. So each time new tab is displayed all of the visual items on that tab are discarded and new visuals for selected item are created.

On the right each item has its own instance of the TabItem. These TabItems are preserved when control switches between tabs and visual tree is not recreated.

Using the original sample

If you would like to try this implementation with sample project associated with original article you need to follow these steps:

  1. Add TabItemGeneratorBehavior.cs file to the project
  2. Modify MainWindow.xaml file to include reference to the new behaviour:
  • Add xmlns:beh="clr-namespace:System.Windows.Controls" to the <Window…> tag.
  • Replace b:PersistTabBehavior with beh:TabItemGeneratorBehavior on the <TabControl... tag.

History

  • 04/05/2012 - Initial publication.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior)
United States United States
Senior Software Engineer with over 20+ years of experience in variety of technologies, development tools and programming languages.

Microsoft Certified Specialist programming in C#, JavaScript, HTML, CSS

Comments and Discussions

 
QuestionProblem when using Validation.ErrorTemplate Pin
Jiri V13-Nov-13 2:54
Jiri V13-Nov-13 2:54 
QuestionPeer review request Pin
Ivan Krivyakov11-Sep-12 16:04
Ivan Krivyakov11-Sep-12 16:04 
AnswerRe: Peer review request Pin
Eugene Sadovoi27-Feb-13 7:35
Eugene Sadovoi27-Feb-13 7:35 
GeneralThank you! Pin
Matt Korth26-Jul-12 2:48
Matt Korth26-Jul-12 2:48 
GeneralRe: Thank you! Pin
Eugene Sadovoi26-Jul-12 8:28
Eugene Sadovoi26-Jul-12 8:28 
BugRe: Thank you! Pin
Matt Korth14-Nov-12 9:20
Matt Korth14-Nov-12 9:20 
QuestionThanks for the article Pin
JasonChing17-Jul-12 22:05
JasonChing17-Jul-12 22:05 
AnswerRe: Thanks for the article Pin
Eugene Sadovoi18-Jul-12 4:36
Eugene Sadovoi18-Jul-12 4:36 
Generalreally useful Pin
sthotakura3-Jul-12 5:21
sthotakura3-Jul-12 5:21 
GeneralRe: really useful Pin
Eugene Sadovoi20-Jul-12 2:33
Eugene Sadovoi20-Jul-12 2:33 
GeneralMy vote of 5 Pin
Manele4-Jun-12 5:32
Manele4-Jun-12 5:32 
GeneralRe: My vote of 5 Pin
Eugene Sadovoi4-Jun-12 8:08
Eugene Sadovoi4-Jun-12 8:08 
QuestionAh the old WPF TabControl love it Pin
Sacha Barber9-Apr-12 7:00
Sacha Barber9-Apr-12 7:00 
AnswerRe: Ah the old WPF TabControl love it Pin
Eugene Sadovoi9-Apr-12 7:13
Eugene Sadovoi9-Apr-12 7:13 
AnswerRe: Ah the old WPF TabControl love it Pin
Pete O'Hanlon9-Apr-12 9:38
subeditorPete O'Hanlon9-Apr-12 9:38 
AnswerRe: Ah the old WPF TabControl love it Pin
guton12-Aug-12 8:54
guton12-Aug-12 8:54 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.