Click here to Skip to main content
Click here to Skip to main content
Go to top

TabStrip within ASP.NET 2.0 - Building a Composite Control

, 29 Sep 2006
Rate this:
Please Sign up or sign in to vote.
A WebForms TabStrip control.

Sample Image - TabularMultiView.jpg

Introduction

In this article, I will explain how to create a tab strip control within ASP.NET 2.0 using existing controls. We all had hoped that with the release of .NET 2.0, Microsoft would incorporate many WebForm controls required for every day use, such as a TabStrip, LoginXXX, etc. They provided us with more controls than we know what to do with, however, there is still no tab strip control within ASP.NET 2.0. But there is good news. With three of the new 2.0 controls (System.Web.UI.WebControls.MultiView, System.Web.UI.WebControls.View, and System.Web.UI.WebControls.Menu), a tab strip is actually quite easy to build.

Instead of building a WebForms page with these controls incorporated into the page, I will build a System.Web.UI.WebControls.CompositeControl, which is also new within the 2.0 framework.

CompositeControl

Microsoft MSDN: "A CompositeControl is an abstract class that provides naming container and control designer functionality for custom controls that encompass child controls in their entirety, or use the functionality of other controls... The CompositeControl class implements the INamingContainer interface. This is required to ensure that all child control ID attributes are unique, and can be located on post back for data binding."

I think you can tell where I am headed… I am going to build a composite control that contains an embedded MultiView, View, and Menu to mimic the look and feel of a tabstrip. All I need to do is add the MultiView, View, and Menu controls into the CompositeControl's control hierarchy (in the correct order, of course), and let each of the controls render themselves. The advantage of using existing controls is that they know how to render themselves, therefore I do not have to write any rendering logic.

I not going to examine the MultiView, View, and Menu controls in detail, however. You will need to have a thorough understanding of these controls before proceeding. Therefore, the links below will take you to MSDN, if needed:

Building the CompositeControl – TabularMultiView

Now that you have a thorough understanding of the basic functionality of each control, I will use them as follows to mimic a tabstrip. The Menu control will be used to display the actual tabs, such that, each MenuItem will represent a tab in a horizontal fashion. The MultiView will contain the Views, in which each View will contain the content for a particular tab. There will be a 1 to 1 correspondence to each MenuItem and View. Meaning tab 0, or MenuItem 0 will be associated with View 0, tab 1 with View 1, etc.

The base functionality provided by the MultiView, View, and Menu controls is sufficient to build a tab strip. To make it more developer friendly, I needed to extend the View control to incorporate additional properties and events. Therefore, I created a TabularView class, which extends the View control. The following properties were added:

  • TabName (String) – MenuItem’s Text property.
  • Selectable (Boolean) – Whether or not the tab is selectable.
  • Tooltip (String) – Tooltip for the MenuItem.
Public Class TabularView
     Inherits View

     Public Property TabName as String
         ...
     End Property
     Public Property Selectable as Boolean
         ...
     End Property
     Public Property ToolTip as String
         ...
     End Property

     ...

End Class

Now to the Real Code

The composite control will be named TabularMultiView, which inherits CompositeControl.

Public Class TabularMultiView 
       Inherits CompositeControl 
End Class

Without going into too much detail about the CompositeControl class, one of the most important methods is the CreateChildControls() method. This method is used to build the control’s control hierarchy. Thus, this is where the embedded Menu and MultiView controls are added to the control hierarchy, such as:

Protected Sub CreateChildControls()
    …
    Dim menu as 
    new Menu
    Dim mltView as new MultiView

    Me.Controls.Add(menu)
    Me.Controls.Add(mltView)
    …
End Sub

Note: The code above does not produce anything meaningful.

Now I needed a way to embed each tab's content within this new TabularMultiView control. More specifically, how was I going to take advantage of my TabularView control, which extends System.Web.UI.WebControls.View? This is done by creating a strongly-typed collection of TabularViews and adding a property named 'ParseChildren' to the TabularMultiView control to allow inner-property controls of type TabularView.

This is accomplished with the following:

DefaultProperty("Views"), _
ParseChildren(True, "Views")> _
Public Class TabularMultiView
    Inherits CompositeControl 

    private _List as List(Of TabularView)

    <Category("Behavior"), _
    Description("The TabularView collection"), _
    DesignerSerializationVisibility  _
    (DesignerSerializationVisibility.Content), _
    PersistenceMode(PersistenceMode.InnerDefaultProperty)> _
    Public ReadOnly Property Views() As List(Of TabularView)
        Get
           If _List Is Nothing Then
                _List = New List(Of TabularView)
           End If
       Return _List
        End Get
    End PropertyEnd Class

As you can see, the TabularMultView's Views property is assigned a strongly-typed collection of TabularViews. The design-time code would look something like the following:

<cc:TabularMultiView ID="tabMltView" runat="server">
   <cc:TabularView ID="TabularView1" runat="server" 
                      TabName="TabName1">
        Content Here…
   </cc:TabularView>
   <cc:TabularView ID="TabularView2" runat="server" 
                      TabName="TabName2">
        Content Here…
   </cc:TabularView>
</cc:TabularMultiView>

The TabularMultView's Views property will be set prior to the control's Load event. It will be done automatically, thanks to the 'ParseChildren' class property. Since the TabularView extends the View, there isn’t much that you need to do to add the TabularViews to the Multiview's Views collection, other than iterating through the TabularMultiView's Views property to extract each TabularView and adding each TabularView to the internal Multiview’s Views collection. Such as:

For Each tabView As TabularView In Views
   InnerMultiView.Views.Add(tabView)
Next

To assign the ActiveIndex of the MultView, add an ActiveIndex property to the TabularMultiView control. Once you have built the MultiView and added each TabularView to its Views collection, you will need to set the ActiveIndex value. I will do it within the CreateChildControls method, for simplicity.

If InnerMultiView.Views.Count >= 0 AndAlso Me.ActiveIndex _ 
                           < InnerMultiView.Views.Count Then
     InnerMultiView.ActiveViewIndex = Me.ActiveIndex
End If

Incorporating the Menus - Tabs

As you are iterating through the TabularMultView's Views collection and adding each TabularView to the MultiView's Views collection, we need to add a new MenuItem to the Menu control as well.

For Each tabView As TabularView In Views
    InnerMultiView.Views.Add(tabView)
    InnerMenu.Items.Add(new MenuItem(“name”, “value”))
Next

Remember, we added the TabName property to the TabularView? This TabName property of the TabularView will become the MenuItem’s Text value. The same can be applied for the Selectable property and so forth. Also, we need to assign each MenuItem’s Value property, so when the MenuItem is clicked, we can associate the MenuItem/Tab with the appropriate TabularView. More specifically, when a MenuItem is clicked, the value of the MenuItem will dictate the ActiveIndex property of the MultiView. Now, we have the following:

Dim index as Integer = 0
Dim menuItem as MenuItem
For Each tabView As TabularView In Views
   ' Views
   InnerMultiView.Views.Add(tabView)  
   ' Menu items - tabs
   menuItem = new MenuItem(tabView.TabName, index)
   menuItem.Selectable = tabView.Selectable
   InnerMenu.Items.Add(new menuItem)
   index += 1
Next

After initializing the Menu, and prior to rendering, add a menu OnClick handler (ideally in the CreateChildControls method):

InnerMenu = New Menu()
AddHandler m_Menu.MenuItemClick, AddressOf Menu_MenuItemClick

Within the menu's Click handler, extract the selected MenuItem's value which will be the index we assigned previously (see above). Then, assign the ActiveIndex of the MultiView to the MenuItem's value.

Protected Sub Menu_MenuItemClick(ByVal sender As System.Object, _
          ByVal e As System.Web.UI.WebControls.MenuEventArgs)_
          InnerMultiView.ActiveViewIndex = CInt(e.Item.Value)

     ' Inform the user of item click event
     RaiseEvent MenuItemClick(sender, e)
End Sub

Putting it all Together - CreateChildControls() Method

Protected Overrides Sub CreateChildControls() 

        InnerMenu = New Menu() 
        ' Capture Menu Item click event, and change
        ' the ActiveIndex on the MultiView
        AddHandler m_Menu.MenuItemClick, AddressOf Menu_MenuItemClick 
        InnerMenu.ID = "tigerMenu"

        InnerMenu.Orientation = Orientation.Horizontal
        InnerMenu.CssClass = Me.TabularMenuCSS 
            
        ' Static Menu Item Style
        If String.IsNullOrEmpty(Me.TabularMenuItemCSS) Then
             InnerMenu.StaticMenuItemStyle.BackColor = Color.DarkGray
             InnerMenu.StaticMenuItemStyle.ForeColor = Color.White
        Else
             InnerMenu.StaticMenuItemStyle.CssClass = Me.TabularMenuItemCSS
             InnerMenu.StaticMenuItemStyle.HorizontalPadding = 0
             InnerMenu.StaticMenuItemStyle.VerticalPadding = 0
         End If 

        ' Static Selected Style
        If String.IsNullOrEmpty(Me.TabularMenuItemCSS) Then
             InnerMenu.StaticSelectedStyle.BackColor = Color.LightGray
             InnerMenu.StaticSelectedStyle.ForeColor = Color.White
        Else
             InnerMenu.StaticSelectedStyle.CssClass = _
                                    Me.TabularMenuSelectedItemCSS
             InnerMenu.StaticSelectedStyle.HorizontalPadding = 0
             InnerMenu.StaticSelectedStyle.VerticalPadding = 0
        End If 
 
        Dim index As Integer = 0
        Dim mItem As MenuItem
           
        For Each tabView As TabularView In Views
            mItem = New MenuItem(IIf(String.IsNullOrEmpty(tabView.TabName), _
                        SetTabTextWidth(tabView.ID), _
                        SetTabTextWidth(tabView.TabName)), _
                        index.ToString()) 

            mItem.Selected = IIf(ActiveIndex.Equals(index), True, False)
            mItem.Selectable = IIf(tabView.Selectable, True, False)
            mItem.ToolTip = IIf(String.IsNullOrEmpty(tabView.TabToolTip), _
                                "", tabView.TabToolTip)
            InnerMenu.Items.Add(mItem)
            index += 1
                   
        Next 

         InnerMultiView = New MultiView()
         InnerMultiView.ID = "tigerMltView"
         For Each tabView As TabularView In Views
              InnerMultiView.Views.Add(tabView)
         Next 

         If InnerMultiView.Views.Count >= 0 AndAlso ActiveIndex < _
                             InnerMultiView.Views.Count Then
              InnerMultiView.ActiveViewIndex = ActiveIndex
         End If

         AddHandler m_MultiView.ActiveViewChanged, AddressOf _
                                       Mlt_ActiveIndexChanged

         Me.Controls.Add(InnerMenu)
         Me.Controls.Add(InnerMultiView)
End Sub

The Look and Feel

The Menu control that’s embedded into this TabularMultiView control can be assigned a cascading style sheet. I have supplied small images which can be used to round the edges of the MenuItems to mimic the look and feel of a tab. It is all up to you. Download my example solution attached to this article, run it, and play with the cascading style sheet properties. The image accompanying this article (top) shows my cascading style sheet in action.

Wrap-Up

The code that I have supplied along with this article contains many more features and functionality. These features exist only to provide additional functionality; however, they do not impact the TabStrip’s basic functionality. I have also included the control's designer. I could not find a way to use the existing MultiView designer; however, I am working on implementing a more robust designer. The existing designer spits out the control name and description within the Visual Studio custom control box. The reason you cannot use the existing MultiView designer is because the MultiView’s designer only accepts inner property controls of type System.Web.UI.WebControls.View. You can use the accompanied code to see how all of this is put together. Happy coding…!

Updates

  • 7/15/06 - Original release.
  • 7/21/06 - Code update.
    • Added a helper method used to update the ActiveIndex (active tab).
    • Added a download for just the code (class files).
  • 9/14/06 - Code update.
    • Fixed ViewState bug.
      • Didn't retain viewstate in certain scenarios on postback.
  • 9/28/06 - Code update (bugs fixed).
    • Retaining Viewstate and setting the Active Index
      • Instead of setting the active tab within the markup, you now set the active tab on page load using 'SetActiveView' (zero-based index). With no active index set, an error is thrown. Therefore, on page load and when not in a postback, simply set the active view index to the desired tab. This will fix viewstate issues.
    • Tab properties
      • Allows you to change tab properties such as 'Selectable', 'Name', et. al. on postback.
    • Project type
      • Changed project download demo from a Web application project to a Web site project to alleviate some users' issues.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

Share

About the Author

Stuart Saltzman
Web Developer
United States United States
Stuart Saltzman is a software engineer at CACI, Inc. He holds both
an undergraduate and graduate degree in Computer Science.
Most, if not all of his latest developement projects have been written
in .NET. He is also a Microsoft Certified Professional and Microsoft Certified Technology Specialist - .NET.

Comments and Discussions

 
GeneralFYI - ajaxcontroltoolkit compatibility. PinmemberPogo12330-Oct-09 7:44 
GeneralRe: FYI - ajaxcontroltoolkit compatibility. PinmemberMember 3831539-Dec-10 15:38 
GeneralControl rendering instead of page rendering Pinmemberp_kolomeytsev21-Apr-09 20:56 
QuestionPrev and NExt - set active index not working Pinmembersetvij19-Apr-09 0:39 
GeneralGreat article! Pinmemberbdaniel710-Dec-07 10:39 
QuestionHow to register composite controls Pinmemberxccx5-Dec-07 20:50 
QuestionChanging Active Tab Programmatically Not Working Pinmembergjsduarte27-Jul-07 4:27 
NewsC# version with Design Time Support Pinmemberdeerchao9-Jul-07 21:13 
GeneralPlz Help PinmemberJats_4ru25-Jun-07 19:16 
Generalrun time add tab Pinmemberpiyush741982016-Feb-07 19:23 
QuestionJavascript exception after postback PinmemberUSSHerm10-Jan-07 13:38 
GeneralRe: Javascript exception after postback PinmemberUSSHerm10-Jan-07 17:36 
AnswerRe: Javascript exception after postback Pinmembersohail.2311-Jan-07 5:13 
GeneralRe: Javascript exception after postback PinmemberUSSHerm11-Jan-07 5:19 
GeneralRe: Javascript exception after postback [modified] Pinmembersohailsayed11-Jan-07 21:12 
GeneralRe: Javascript exception after postback Pinmembersohailsayed12-Jan-07 7:00 
GeneralRe: Javascript exception after postback PinmemberStuart Saltzman12-Jan-07 18:08 
AnswerRe: Javascript exception after postback PinmemberUSSHerm14-Jan-07 18:41 
GeneralRe: Javascript exception after postback PinmemberScott T.28-Feb-07 6:41 
GeneralAdding tabs dynamically Pinmembermikecano8-Jan-07 12:21 
GeneralRe: Adding tabs dynamically PinmemberStuart Saltzman8-Jan-07 16:53 
GeneralTab Text Size PinmemberJason Tepe13-Nov-06 13:54 
GeneralRe: Tab Text Size PinmemberJason Tepe13-Nov-06 14:14 
AnswerRe: Tab Text Size PinmemberStuart Saltzman14-Nov-06 16:50 
QuestionCan this control become container control? Pinmemberchenhuauestc15-Oct-06 22:32 
AnswerRe: Can this control become container control? PinmemberStuart Saltzman16-Oct-06 15:04 
QuestionChange tab name in Page_Load PinmemberUnderWing25-Sep-06 7:48 
AnswerRe: Change tab name in Page_Load PinmemberStuart Saltzman26-Sep-06 9:07 
QuestionRe: Change tab name in Page_Load Pinmemberjhildeman28-Sep-06 8:20 
AnswerRe: Change tab name in Page_Load PinmemberStuart Saltzman28-Sep-06 12:47 
AnswerRe: Change tab name in Page_Load PinmemberStuart Saltzman28-Sep-06 14:22 
AnswerRe: Change tab name in Page_Load PinmemberStuart Saltzman28-Sep-06 14:23 
QuestionC# Version Pinmembernetvasu19-Sep-06 4:58 
AnswerRe: C# Version PinmemberSinghalManu2-May-07 9:41 
Generalgood work Pinmembervik2016-Sep-06 1:09 
GeneralViewState lost Pinmemberjpasman31-Aug-06 3:03 
GeneralRe: ViewState lost PinmemberStuart Saltzman3-Sep-06 15:35 
AnswerRe: ViewState lost Pinmembercreese7-Sep-06 13:36 
GeneralRe: ViewState lost PinmemberStuart Saltzman7-Sep-06 18:29 
GeneralRe: ViewState lost Pinmemberjpasman8-Sep-06 2:55 
GeneralNullReferenceException Pinmemberjpasman29-Aug-06 5:36 
GeneralRe: NullReferenceException PinmemberStuart Saltzman29-Aug-06 12:54 
GeneralRe: NullReferenceException Pinmemberjpasman30-Aug-06 2:21 
Generalmsg to the author. Pinmembergengire26-Aug-06 2:07 
GeneralRe: msg to the author. PinmemberSinghalManu2-May-07 9:44 
GeneralWebAppDemp.dll PinmemberAgilitySix24-Aug-06 15:07 
GeneralRe: WebAppDemp.dll PinmemberStuart Saltzman25-Aug-06 3:53 
GeneralError when databound control is placed inside any TabularView Pinmembernycapple31-Jul-06 3:51 
GeneralRe: Error when databound control is placed inside any TabularView PinmemberStuart Saltzman31-Jul-06 5:41 
GeneralRe: Error when databound control is placed inside any TabularView Pinmembernycapple31-Jul-06 5:45 

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

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

| Advertise | Privacy | Mobile
Web04 | 2.8.140926.1 | Last Updated 29 Sep 2006
Article Copyright 2006 by Stuart Saltzman
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid