Click here to Skip to main content
15,868,016 members
Articles / Desktop Programming / Windows Forms

TreeTabControl. A Tree of Tab Items

Rate me:
Please Sign up or sign in to vote.
4.67/5 (11 votes)
28 Mar 2010CPOL5 min read 38.8K   3.4K   33   2
Handling a tree of customized tab items

Introduction

This project is based in a WPF User Control which is composed of two main controls: a TreeView and a TabControl.

The idea came up when I was investigating about how to customize the Tab items modifying their headers' appearance by adding the typical button for closing themselves. Furthermore, I was developing a project where I needed TabItems that could be containers of more TabItems, like another TabControl. The reason is because the control contains the TreeView. With the TreeView, one can view the tree of TabItems displayed and get a quicker route to handle them.

TreeTabControl.jpg

Background

  1. TreeTabControl is the User Control that we must use it in our own project. The property called SelectedTabItem gets the current TreeTabItem that is in use. By using the property called IsTreeExpanded or the methods HideTree() and ShowTree() we can hide or show the TreeView.
  2. TreeTabItem is a object that inherits from TabItem and implements the IDisposable interface. This object has been created in order to make easier the creation of TabItems with the customized header. Through its constructor, we can create the TreeTabItems with the button for closing themselves whether we want or not. The Header property has been altered and just accepts a User Control called TabHeader. That user control is responsible to give the TabItem that appearance by adding the closing button and the label with the name of the TabItem.
  3. TreeTabItemGroup is an object that inherits from TreeTabItem. When that object is created, it contains a TabControl in order to be able to hold more TreeTabItems.
  4. TreeItem is an object that inherits from TreeViewItem. The main feature that this object has is that it contains a pointer for the TreeTabItem linked to the object. Then, depending of the type of the TreeTabItem linked and its features, the TreeItem created will be able to add the corresponding ContextMenuItems. For instance, if the TreeTabItem linked can be closed and its type is a TreeTabItemGroup -can hold a collection of items- it will add the following ContextMenuItems: for closing the TreeTabItem and itself; for expanding the collection of items that it has; for collapsing the collection; for showing the linked TreeTabItem. In case the TreeTabItem could not be closed, it would not contain the ContextMenuItem for closing the tab. Those ContextMenuItems can be customized by adding our icons. This I will explain in another section.
  5. TreeTabConfig is the object responsible for getting the configuration of the control. As a lot of you already know, the configuration files that .NET offers can only be used at the main project that is running. Let me explain a bit better. If we have a project which needs a configuration file for a User Control that it is using, that configuration info will be got from the configuration file of the main project not for the configuration file of the User Control. So, I wanted to get more flexibility. TreeTabConfig will get the information included in its configuration file inside the folder where the library is running. In that file, one can define the path where the icons of the ContextMenuItems can be found, or whether we want to disable those menus with icons. Of course, more configuration keys can be added there. This object contains a couple of methods in order to get the resized Image object from the icon file.
  6. DisposingMethod. Well, maybe this class should not be included here, but finally I decided to leave it. The purpose of that class was to execute a method declared outside the TreeTabControl once a TreeTabItem is collected by the garbage collector, in other words, when it is removed from the memory. Perhaps someone might find some utility for it. I wanted to get the control when a TreeTabItem is closed and disposed from the collection and I wanted to execute a method when it happens. Since WPF does not support the event for disposing a object, I found this way to do it. It is easy, basically it works in the following way: TreeTabItem implements IDisposable. When the method Close() is called, it registers itself for the next garbage's recollection. TreeTabItem has a destructor. When the destruction of the object is happening, the object checks whether its property DisposingMethod is not null. In that case, it will execute the reflected method in the DisposingMethod object through the Execute method. Also, notice that the content of the TreeTabItem must implement the IDisposable interface because when the TreeTabItem is closed, it will call to the Dispose() method of its content. So, if we are interested in that, when our tab is closing itself and we want that an event happens in our content's control, we can prepare the Dispose() method for do it. Or in case the method is outside the content's control, we can use the class DisposingMethod.

Using the Code

Adding the TreeTabControl to your Application

First of all, you must add the reference of the library in your project. Go to “References-> Add Reference...-> Browse” and select the library. Once the library added, we must declare the assembly at the header of our application creating the namespace used for the control. E.g.:

XML
<window margin="0,0,0,0" title="Window1" 
xmlns:custom="clr-namespace:TreeTab;assembly=TreeTab" 
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
x:class="TreeTabTest.Window1">

Once declared, we can add the control. E.g:

XML
<custom:TreeTabControl Name="treeTab" IsTreeExpanded="True">

Hiding and Showing the TreeView

As I before said, one can show and hide the TreeView if one thinks it is useless. It is quite simple, we just have to toy with the parent grid's columns, removing and creating the column and setting the visibility of the control.

C#
public void HideTree()
{
    if (this.isTreeExpanded)
    {
        this.treeView.Visibility = Visibility.Collapsed;
        this.ContentGrid.ColumnDefinitions.RemoveAt(0);
        this.isTreeExpanded = false;
    }
}

public void ShowTree()
{
    if (!this.isTreeExpanded)
    {
        ColumnDefinition col = new ColumnDefinition();
        col.Width = new GridLength(150);
        this.ContentGrid.ColumnDefinitions.Insert(0, col);
        this.treeView.Visibility = Visibility.Visible;
        this.isTreeExpanded = true;
    }
}

Adding a Tab Without Closing Button on its Header

C#
private void btnAddTab1_Click(object sender, RoutedEventArgs e)
{
    this.treeTab.AddTabItem("one", "Main Tab", false, TreeItem.TREEITEM_TYPE.MAIN);
}

Adding Three Tab to Another Parent Tab

Notice that the object called <treetab> is the instance. When adding a new <treetabitem> to the collection, notice that its <id> must be unique. If the control finds out that the new <id> you are trying to use is already in use, the new TreeTabItem will be ignored and will not be added. E.g:

C#
private void btnAddTab3_Click(object sender, RoutedEventArgs e)
{
    TreeTabItemGroup tParent = (TreeTabItemGroup) this.treeTab.GetTabItemById("two");
    TreeTabItem tItem = this.treeTab.AddTabItem
	("tree", "Child Group 1", true, TreeItem.TREEITEM_TYPE.MAIN, tParent);
    TreeTabIGroupGrid grid = new TreeTabIGroupGrid();
    grid.Children.Add(new Example());
    this.treeTab.SetTabContent(tItem, grid);
    this.treeTab.AddTabItem("four", "Child Group 2", 
	true, TreeItem.TREEITEM_TYPE.MAIN, tParent);
    this.treeTab.AddTabItem("five", "Child Group 3", 
	true, TreeItem.TREEITEM_TYPE.MAIN, tParent);
}

Linking Icon Files to the ContextMenuItem

When you want to add a new <contextmenuitem> to the collection and you wish that the item is displayed with its custom icon, you must create with the same <id> key you will use in the configuration file section. E.g.:

XML
<configSections>
  <section name="ContextMenuIcons"
  type="System.Configuration.SingleTagSectionHandler" />
</configSections>
<ContextMenuIcons>
  <icon id="Close" fileName="LinkBack.ico"/>
  <icon id="Expand" fileName="Add.ico"/>
  <icon id="Collapse" fileName="Remove.ico"/>
  <icon id="Show" fileName=""/>
</ContextMenuIcons>

History

  • 28th March, 2010: Initial post

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)
Spain Spain
http://www.linkedin.com/in/gerard-castello-viader
https://github.com/gcastellov

Comments and Discussions

 
GeneralMy vote of 1 Pin
riodejenris8-Dec-11 22:54
riodejenris8-Dec-11 22:54 
GeneralCool Idea, Original! Pin
KentuckyEnglishman1-Apr-10 2:15
KentuckyEnglishman1-Apr-10 2:15 

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.