Collection disappearing at run time

Discussion in 'ASP .Net Building Controls' started by lisa@starways.net, Apr 29, 2005.

  1. Guest

    I really, really wanted to finish this one without asking anyone for
    help. But I've been beating my head against this thing, and I'm
    getting nowhere.

    I wrote a tab control. I cribbed some ideas from the BlueValley one,
    but mostly after I'd finished the main stuff.

    It works just great in design time (the opposite of the usual problem).
    Except that if I try to add any content to any of the tabs in the HTML
    view, when I go back to design view, the control won't render anymore.
    The same thing happens if I try adding content to a tab
    programmatically. At least I think. The problem with knowing for sure
    is that if I try to view a page that has a tab control on it, whether I
    add content or not, the same thing happens, and I get an error.

    When I trace the error, I find that either running the page or adding
    content in HTML view or both causes the tabs collection to evaporate
    into Nothing.

    I've tried debugging in every way I can, but I can't figure out what's
    making the collection not persist. I'm posting the code here. Feel
    free to take it and use it for yourself, if it becomes fixable. But if
    anyone can tell me what I'm doing wrong, I'd very much appreciate it.

    Um... it's IE only. Again. Sorry.

    TIA,
    Lisa

    Imports System.ComponentModel
    Imports System.ComponentModel.Design
    Imports System.Web.UI
    Imports System.IO
    Imports System.Web.UI.WebControls
    Imports System.Web.UI.HtmlControls

    <ToolboxData("<{0}:TabStrip runat=server></{0}:TabStrip>"),
    Designer(GetType(TabStripDesigner)), PersistChildren(False),
    ParseChildren(True, "Tabs"), DefaultProperty("Tabs"),
    DefaultEvent("SelectedIndexChanged")> _
    Public Class TabStrip
    Inherits WebControl
    Implements INamingContainer, IPostBackDataHandler,
    IPostBackEventHandler

    Private _tabs As New TabCollection
    Private _tabsPerRow As Integer = 3
    Private _tabHeight As New Unit(25, UnitType.Pixel)
    Private _width As New Unit(300, UnitType.Pixel)
    Private _height As New Unit(250, UnitType.Pixel)
    Private _selectedIndex As Integer = 0
    Private _autoPostBack As Boolean = False
    Private _tabCount As Integer

    Private _tabRows As Integer
    Private _fullRows As Integer
    Private _tabsInPartRow As Integer
    Private _tabsInFullRow As Integer
    Private _fullRowTabWidth As Unit
    Private _partRowTabWidth As Unit
    Private _fullRowRemainder As Integer
    Private _partRowRemainder As Integer
    Private _tabPageHeight As Unit
    Private _visibleTabs As Integer
    Private _rowArray As Pair()()
    Private _selectedRow As Integer
    Private _tabIdx As Integer
    Private _firstVisibleTabIdx As Integer = -1

    <Category("Behavior"), Description("The collection of tabs."),
    DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
    NotifyParentProperty(True),
    PersistenceMode(PersistenceMode.InnerDefaultProperty)> _
    Public ReadOnly Property Tabs() As TabCollection
    Get
    Return _tabs
    End Get
    End Property

    <Category("Appearance"), Description("The maximum number of tabs in
    a row."),
    DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
    NotifyParentProperty(True), PersistenceMode(PersistenceMode.Attribute)>
    _
    Public Property TabsPerRow() As Integer
    Get
    Return _tabsPerRow
    End Get
    Set(ByVal Value As Integer)
    _tabsPerRow = Value
    End Set
    End Property 'TabsPerRow

    <Category("Appearance"), Description("The height of each tab
    row.")> _
    Public Property TabHeight() As Unit
    Get
    Return _tabHeight
    End Get
    Set(ByVal Value As Unit)
    If Not Value.Type = UnitType.Pixel Then
    Throw New ArgumentException("TabHeight must be given in
    pixels.")
    End If
    _tabHeight = Value
    End Set
    End Property 'TabHeight

    <Category("Appearance"), Description("The width of the control.")>
    _
    Public Overrides Property Width() As Unit
    Get
    Return _width
    End Get
    Set(ByVal Value As Unit)
    If Not Value.Type = UnitType.Pixel Then
    Throw New ArgumentException("Width must be given in
    pixels.")
    End If
    _width = Value
    End Set
    End Property 'Width

    <Category("Appearance"), Description("The height of the control.")>
    _
    Public Overrides Property Height() As Unit
    Get
    Return _height
    End Get
    Set(ByVal Value As Unit)
    If Not Value.Type = UnitType.Pixel Then
    Throw New ArgumentException("Height must be given in
    pixels.")
    End If
    _height = Value
    End Set
    End Property 'Height

    <Browsable(False)> _
    Public Property SelectedIndex() As Integer
    Get
    Return _selectedIndex
    End Get
    Set(ByVal Value As Integer)
    _selectedIndex = Value
    End Set
    End Property

    <DefaultValue(True)> _
    Public Property AutoPostBack() As Boolean
    Get
    Return _autoPostBack
    End Get
    Set(ByVal Value As Boolean)
    _autoPostBack = Value
    End Set
    End Property

    Protected Overrides Sub OnInit(ByVal e As EventArgs)
    MyBase.OnInit(e)
    If AutoPostBack And Not (Page Is Nothing) Then
    Page.RegisterRequiresPostBack(Me)
    End If
    End Sub 'OnInit

    Protected Overrides Sub LoadViewState(ByVal viewState As Object)
    If Not (viewState Is Nothing) And _autoPostBack Then
    _selectedIndex = Int32.Parse(CType(viewState, String))
    Else
    MyBase.LoadViewState(viewState)
    End If
    End Sub 'LoadViewState

    Protected Overrides Function SaveViewState() As Object
    ' If AutoPostBack is set, save the SelectedTab to the view
    state for postback scenarios
    If _autoPostBack Then
    Return _selectedIndex.ToString()
    Else
    Return MyBase.SaveViewState()
    End If
    End Function 'SaveViewState

    #Region "Overriden methods"

    Protected Overrides Sub OnPreRender(ByVal e As System.EventArgs)

    'this script is client script and should appear only once
    If Not Page.IsClientScriptBlockRegistered("TabStrip_vbs") Then
    Dim reader As New
    System.IO.StreamReader(Me.GetType().Assembly.GetManifestResourceStream(Me.GetType(),
    "TabStrip.vbs"))
    Dim script As String = "<script language='vbscript'
    type='text/vbscript' >" _
    + ControlChars.CrLf _
    + "<!--" _
    + ControlChars.CrLf _
    + reader.ReadToEnd() _
    + ControlChars.CrLf _
    + "//-->" _
    + ControlChars.CrLf _
    + "</script>"
    Page.RegisterClientScriptBlock("TabStrip_vbs", script)

    reader = Nothing
    script = Nothing
    End If

    End Sub 'OnPreRender

    Private Function GetSelectedIndexForRender() As Integer

    If Tabs.Count > 0 Then
    ' Get the Selected Index.
    ' For a non-AutoPostBack TabControl, the selected index
    ' is stored in a cookie.
    ' Otherwise, it is stored as a property of the TabControl.
    If Not _autoPostBack And Not (Page Is Nothing) Then
    _selectedIndex = 0
    Dim cookie As System.Web.HttpCookie =
    Page.Request.Cookies((Me.UniqueID + "_SelectedIndex"))
    If Not (cookie Is Nothing) Then
    _selectedIndex = Int32.Parse(cookie.Value)
    End If
    If _selectedIndex < 0 Or _selectedIndex > _tabCount - 1
    Then
    _selectedIndex = 0
    End If
    End If

    'if the selected tab isn't visible and enabled, it can't be
    selected
    If Tabs(_selectedIndex).Visible And
    Tabs(_selectedIndex).Enabled Then
    Return _selectedIndex
    Else
    _selectedIndex = -1
    'get the first tab that's both visible and enabled and
    select it
    For Each myTab As Tab In Tabs
    If myTab.Visible And myTab.Enabled Then
    Return Tabs.IndexOf(myTab)
    Exit For
    End If
    Next
    End If
    End If

    End Function 'GetSelectedIndexForRender

    Private Sub GetTabFormatValuesForRender()

    'get the number of tabs in full rows and their widths
    _tabsInFullRow = TabsPerRow
    _fullRowTabWidth = Unit.Pixel(Math.Floor(Width.Value /
    CDbl(_tabsInFullRow)))

    'get the number of rows, total
    _tabRows = CType(Math.Ceiling(CDbl(_visibleTabs) /
    CDbl(_tabsInFullRow)), Integer)

    'get the number of tabs in a partial row (a row with fewer than
    TabsPerRow tabs)
    If _tabRows * _tabsInFullRow = _visibleTabs Then
    _fullRows = _tabRows
    Else
    _fullRows = _tabRows - 1
    End If
    _tabsInPartRow = _visibleTabs - (_fullRows * _tabsInFullRow)

    'get the widths of tabs in a partial row
    If _tabsInPartRow > 0 Then
    _partRowTabWidth = Unit.Pixel(Math.Floor(Width.Value /
    CDbl(_tabsInPartRow)))
    Else
    _partRowTabWidth = _fullRowTabWidth
    End If

    'but just in case they don't divide roundly, we need the
    remainders
    _fullRowRemainder = Width.Value - _fullRowTabWidth.Value *
    _tabsInFullRow
    _partRowRemainder = Width.Value - _partRowTabWidth.Value *
    _tabsInPartRow

    'figure out the height of the masterPage
    _tabPageHeight = Unit.Pixel(Height.Value - (_tabRows *
    TabHeight.Value))

    'let's make a jagged array that represents the tabs in their
    rows
    'we'll put the tab widths in Pair.Second
    ReDim _rowArray(_tabRows - 1)
    For i As Integer = 0 To _tabRows - 1
    If _fullRows < _tabRows And i = 0 Then
    ReDim _rowArray(i)(_tabsInPartRow - 1)
    For j As Integer = 0 To _tabsInPartRow - 1
    If j = 0 Then
    'add in the remainder
    _rowArray(i)(j) = New Pair(-1,
    Unit.Pixel(_partRowTabWidth.Value + _partRowRemainder))
    Else
    _rowArray(i)(j) = New Pair(-1,
    _partRowTabWidth)
    End If
    Next
    Else
    ReDim _rowArray(i)(_tabsInFullRow - 1)
    For j As Integer = 0 To _tabsInFullRow - 1
    If j = 0 Then
    'add in the remainder
    _rowArray(i)(j) = New Pair(-1,
    Unit.Pixel(_fullRowTabWidth.Value + _fullRowRemainder))
    Else
    _rowArray(i)(j) = New Pair(-1,
    _fullRowTabWidth)
    End If
    Next
    End If
    Next

    'now let's fill that array with tab indices (that goes into
    Pair.First)
    Dim _tabCollectionCounter As Integer = 0
    Dim _tabCounter As Integer = 0
    Dim _rowCounter As Integer = _tabRows - 1

    Do While _tabCollectionCounter < _tabCount
    If Tabs(_tabCollectionCounter).Visible Then
    _rowArray(_rowCounter)(_tabCounter).First =
    _tabCollectionCounter
    If _tabCollectionCounter = _selectedIndex Then
    _selectedRow = _rowCounter
    End If
    _tabCounter = _tabCounter + 1
    If _tabCounter = _tabsInFullRow Then
    _rowCounter = _rowCounter - 1
    _tabCounter = 0
    End If
    End If
    _tabCollectionCounter = _tabCollectionCounter + 1
    Loop

    End Sub 'GetTabFormatValuesForRender

    Protected Overrides Sub Render(ByVal writer As
    System.Web.UI.HtmlTextWriter)

    'get the number of visible tabs
    _visibleTabs = 0
    For Each myTab As Tab In Tabs
    If myTab.Visible Then
    _visibleTabs = _visibleTabs + 1
    End If
    Next

    'if there are no visible tabs, don't render the control
    If _visibleTabs = 0 Then
    Exit Sub
    End If

    'if there is no usable selectedindex, don't render the control
    If GetSelectedIndexForRender() = -1 Then
    Exit Sub
    End If

    'get the arrangement and width of tabs
    GetTabFormatValuesForRender()

    'now let's do the rendering
    writer.AddAttribute(HtmlTextWriterAttribute.Cellpadding, "0",
    False)
    writer.AddAttribute(HtmlTextWriterAttribute.Cellspacing, "0",
    False)
    writer.AddAttribute(HtmlTextWriterAttribute.Border, "0", False)
    writer.AddAttribute(HtmlTextWriterAttribute.Width,
    Width.ToString, False)
    writer.RenderBeginTag(HtmlTextWriterTag.Table)

    'first do the rows other than the selected row
    For i As Integer = 0 To _rowArray.GetUpperBound(0)
    If Not i = _selectedRow Then
    writer.RenderBeginTag(HtmlTextWriterTag.Tr)

    writer.AddAttribute(HtmlTextWriterAttribute.Nowrap,
    "true", False)
    writer.AddAttribute(HtmlTextWriterAttribute.Valign,
    "middle", False)
    writer.RenderBeginTag(HtmlTextWriterTag.Td)

    For j As Integer = 0 To _rowArray(i).GetUpperBound(0)
    _tabIdx = CInt(_rowArray(i)(j).First)
    writer.AddStyleAttribute("border-bottom", "none")
    writer.AddStyleAttribute("height",
    TabHeight.Value.ToString)
    writer.AddStyleAttribute("overflow", "hidden")
    writer.AddStyleAttribute("text-align", "center")
    writer.AddStyleAttribute("font-family", "system")
    writer.AddStyleAttribute("font-size", "8pt")
    writer.AddStyleAttribute("display", "inline")
    writer.AddStyleAttribute("padding-top", "3px")
    writer.AddStyleAttribute("border-left", "3px
    outset")
    writer.AddStyleAttribute("border-top", "3px
    outset")
    writer.AddStyleAttribute("border-right", "3px
    outset")
    writer.AddStyleAttribute("cursor", "hand")
    writer.AddStyleAttribute(HtmlTextWriterStyle.Width,
    CType(_rowArray(i)(j).Second, Unit).ToString)
    writer.AddStyleAttribute(HtmlTextWriterStyle.Color,
    Tabs(_tabIdx).ForeColor.Name)

    writer.AddStyleAttribute(HtmlTextWriterStyle.BackgroundColor,
    Tabs(_tabIdx).BackColor.Name)
    'set the onclick depending on whether AutoPostBack
    is true or not
    If _autoPostBack Then

    writer.AddAttribute(HtmlTextWriterAttribute.Onclick, "jscript:" +
    Page.GetPostBackEventReference(Me, _tabIdx.ToString()), False)
    Else

    writer.AddAttribute(HtmlTextWriterAttribute.Onclick,
    "TabStrip_SelectTab(this)", False)
    End If
    writer.AddAttribute(HtmlTextWriterAttribute.Name,
    "tab_" & _tabIdx.ToString, False)
    writer.AddAttribute(HtmlTextWriterAttribute.Id,
    "tab_" & _tabIdx.ToString, False)

    writer.RenderBeginTag(HtmlTextWriterTag.Div)
    writer.Write(Tabs(_tabIdx).Text)
    writer.RenderEndTag() 'Div
    Next

    writer.RenderEndTag() 'Td
    writer.RenderEndTag() 'Tr
    End If
    Next

    'now do the selected row
    writer.RenderBeginTag(HtmlTextWriterTag.Tr)

    writer.AddAttribute(HtmlTextWriterAttribute.Nowrap, "true",
    False)
    writer.AddAttribute(HtmlTextWriterAttribute.Valign, "middle",
    False)
    writer.RenderBeginTag(HtmlTextWriterTag.Td)

    For j As Integer = 0 To
    _rowArray(_selectedRow).GetUpperBound(0)
    _tabIdx = CInt(_rowArray(_selectedRow)(j).First)
    If _rowArray(_selectedRow)(j).First = _selectedIndex Then
    writer.AddStyleAttribute("border-bottom", "none")
    Else
    writer.AddStyleAttribute("border-bottom", "3px inset")
    End If
    writer.AddStyleAttribute("height",
    TabHeight.Value.ToString)
    writer.AddStyleAttribute("overflow", "hidden")
    writer.AddStyleAttribute("text-align", "center")
    writer.AddStyleAttribute("font-family", "system")
    writer.AddStyleAttribute("font-size", "8pt")
    writer.AddStyleAttribute("display", "inline")
    writer.AddStyleAttribute("padding-top", "3px")
    writer.AddStyleAttribute("border-left", "3px outset")
    writer.AddStyleAttribute("border-top", "3px outset")
    writer.AddStyleAttribute("border-right", "3px outset")
    writer.AddStyleAttribute("cursor", "hand")
    writer.AddStyleAttribute(HtmlTextWriterStyle.Width,
    CType(_rowArray(_selectedRow)(j).Second, Unit).ToString)
    writer.AddStyleAttribute(HtmlTextWriterStyle.Color,
    Tabs(_tabIdx).ForeColor.Name)

    writer.AddStyleAttribute(HtmlTextWriterStyle.BackgroundColor,
    Tabs(_tabIdx).BackColor.Name)
    'set the onclick depending on whether AutoPostBack is true
    or not
    If _autoPostBack Then
    writer.AddAttribute(HtmlTextWriterAttribute.Onclick,
    "jscript:" + Page.GetPostBackEventReference(Me, _tabIdx.ToString()),
    False)
    Else
    writer.AddAttribute(HtmlTextWriterAttribute.Onclick,
    "TabStrip_SelectTab(this)", False)
    End If
    writer.AddAttribute(HtmlTextWriterAttribute.Name, "tab_" &
    _tabIdx.ToString, False)
    writer.AddAttribute(HtmlTextWriterAttribute.Id, "tab_" &
    _tabIdx.ToString, False)
    writer.RenderBeginTag(HtmlTextWriterTag.Div)
    writer.Write(Tabs(_tabIdx).Text)
    writer.RenderEndTag() 'Div
    Next

    writer.RenderEndTag() 'Td
    writer.RenderEndTag() 'Tr

    'so much for the tabs. Now the tab pages/panels
    writer.RenderBeginTag(HtmlTextWriterTag.Tr)
    writer.RenderBeginTag(HtmlTextWriterTag.Td)

    writer.AddStyleAttribute(HtmlTextWriterStyle.BackgroundColor,
    Tabs(_selectedIndex).BackColor.Name)
    writer.AddStyleAttribute("overflow", "auto")
    writer.AddStyleAttribute("border-left", "3px outset")
    writer.AddStyleAttribute("border-bottom", "3px outset")
    writer.AddStyleAttribute("border-right", "3px outset")
    writer.AddStyleAttribute("display", "inline")
    writer.AddStyleAttribute(HtmlTextWriterStyle.Height,
    _tabPageHeight.ToString)
    writer.AddStyleAttribute(HtmlTextWriterStyle.Width,
    Width.ToString)
    writer.RenderBeginTag(HtmlTextWriterTag.Div)

    For Each myTab As Tab In Tabs
    ' Only render the TabView under the following conditions:
    ' (1) AutoPostBack is set to false.
    ' (2) AutoPostBack is set to true, and the TabView is for
    the Selected Tab
    If Not _autoPostBack Or (_autoPostBack And _selectedIndex =
    _tabs.IndexOf(myTab)) Then
    writer.AddStyleAttribute(HtmlTextWriterStyle.Width,
    myTab.InnerWidth.ToString)
    writer.AddStyleAttribute(HtmlTextWriterStyle.Height,
    myTab.InnerHeight.ToString)

    writer.AddStyleAttribute(HtmlTextWriterStyle.BackgroundColor,
    myTab.BackColor.Name)
    writer.AddStyleAttribute(HtmlTextWriterStyle.Color,
    myTab.ForeColor.Name)
    writer.AddStyleAttribute("text-align", "center")
    writer.AddAttribute(HtmlTextWriterAttribute.Id,
    Me.ClientID & "_panel_" & Tabs.IndexOf(myTab).ToString, False)
    writer.AddAttribute(HtmlTextWriterAttribute.Name,
    Me.ClientID & "_panel_" & Tabs.IndexOf(myTab).ToString, False)
    If _selectedIndex = _tabs.IndexOf(myTab) Then
    writer.AddStyleAttribute("display", "inline")
    Else
    writer.AddStyleAttribute("display", "none")
    End If
    writer.RenderBeginTag(HtmlTextWriterTag.Div)

    If myTab.HasControls() = False Then
    myTab.Controls.Add(New LiteralControl("&nbsp;"))
    End If

    For Each myControl As Control In mytab.Controls
    myControl.RenderControl(writer)
    Next

    writer.RenderEndTag() 'Div
    End If
    Next

    writer.RenderEndTag() 'Div
    writer.RenderEndTag() 'Td
    writer.RenderEndTag() 'Tr
    writer.RenderEndTag() 'Table

    End Sub 'Render

    #End Region

    Public Function LoadPostData(ByVal postDataKey As String, ByVal
    postCollection As System.Collections.Specialized.NameValueCollection)
    As Boolean Implements System.Web.UI.IPostBackDataHandler.LoadPostData
    ' Stub Implementation, Required for IPostBackDataHandler
    ' This control must derive from IPostBackDataHandler, even
    though it doesn't use its methods.
    End Function 'LoadPostData

    Public Sub RaisePostDataChangedEvent() Implements
    System.Web.UI.IPostBackDataHandler.RaisePostDataChangedEvent
    ' Stub Implementation, Required for IPostBackDataHandler
    ' This control must derive from IPostBackDataHandler, even
    though it doesn't use its methods.
    End Sub 'RaisePostDataChangedEvent

    Public Sub RaisePostBackEvent(ByVal eventArgument As String)
    Implements System.Web.UI.IPostBackEventHandler.RaisePostBackEvent
    If eventArgument Is Nothing Then
    Return
    End If
    _selectedIndex = Int32.Parse(eventArgument)
    Dim e As New EventArgs
    OnSelectedIndexChanged(e)
    End Sub 'RaisePostBackEvent

    Public Event SelectedIndexChanged As EventHandler

    Public Overridable Sub OnSelectedIndexChanged(ByVal e As EventArgs)
    RaiseEvent SelectedIndexChanged(Me, e)
    End Sub 'OnSelectedIndexChanged

    End Class 'TabStrip

    <ToolboxItem(False)> _
    Public Class Tab
    Inherits Control

    Private _text As String
    Private _innerHeight As Unit
    Private _innerWidth As Unit
    Private _enabled As Boolean
    Private _visible As Boolean
    Private _foreColor As System.Drawing.Color
    Private _backColor As System.Drawing.Color

    Public Sub New(Optional ByVal TabText As String = "Tab")
    Me.Text = TabText
    Me.InnerHeight = Unit.Percentage(100)
    Me.InnerWidth = Unit.Percentage(100)
    Me.Enabled = True
    Me.Visible = True
    Me.ForeColor = System.Drawing.Color.Black
    Me.BackColor = System.Drawing.Color.Silver
    End Sub

    <Browsable(True), Category("Appearance"), Description("The text
    appearing on the tab.")> _
    Public Property Text() As String
    Get
    Return _text
    End Get
    Set(ByVal Value As String)
    _text = Value
    End Set
    End Property 'Text

    <Browsable(True), Category("Appearance"), Description("The height
    of the content of the tab panel (can be greater or less than the height
    of the panel itself).")> _
    Public Property InnerHeight() As Unit
    Get
    Return _innerHeight
    End Get
    Set(ByVal Value As Unit)
    _innerHeight = Value
    End Set
    End Property 'InnerHeight

    <Browsable(True), Category("Appearance"), Description("The width of
    the content of the tab panel (can be greater or less than the width of
    the panel itself).")> _
    Public Property InnerWidth() As Unit
    Get
    Return _innerWidth
    End Get
    Set(ByVal Value As Unit)
    _innerWidth = Value
    End Set
    End Property 'InnerWidth

    <Browsable(True), Category("Behavior"), Description("Whether tab
    can be selected and contents accessed in runtime or not.")> _
    Public Property Enabled() As Boolean
    Get
    Return _enabled
    End Get
    Set(ByVal Value As Boolean)
    _enabled = Value
    End Set
    End Property 'Enabled

    <Browsable(True), Category("Behavior"), Description("Whether tab is
    visible at runtime or not.")> _
    Public Overrides Property Visible() As Boolean
    Get
    Return _visible
    End Get
    Set(ByVal Value As Boolean)
    _visible = Value
    End Set
    End Property 'Visible

    <Browsable(True), Category("Appearance"), Description("The color of
    the text appearing on the tab.")> _
    Public Property ForeColor() As System.Drawing.Color
    Get
    Return _foreColor
    End Get
    Set(ByVal Value As System.Drawing.Color)
    _foreColor = Value
    End Set
    End Property 'ForeColor

    <Browsable(True), Category("Appearance"), Description("The
    background of the tab.")> _
    Public Property BackColor() As System.Drawing.Color
    Get
    Return _backColor
    End Get
    Set(ByVal Value As System.Drawing.Color)
    _backColor = Value
    End Set
    End Property 'BackColor

    End Class 'Tab

    Public Class TabCollection
    Inherits CollectionBase

    Default Public ReadOnly Property Item(ByVal index As Integer) As
    Tab
    Get
    Return CType(MyBase.List(index), Tab)
    End Get
    End Property 'Item

    Public Sub Add(ByVal myTab As Tab)
    MyBase.List.Add(myTab)
    End Sub 'Add

    Public Function IndexOf(ByVal myTab As Tab) As Integer
    Return MyBase.List.IndexOf(myTab)
    End Function 'IndexOf

    End Class 'TabCollection

    Public Class TabStripDesigner
    Inherits System.Web.UI.Design.ControlDesigner

    Private verbAddTab As DesignerVerb
    Private verbShowNextTab As DesignerVerb
    Private verbRemoveTab As DesignerVerb
    Private DesignTimeSelectedIndex As Integer

    Public Sub New()
    verbAddTab = New DesignerVerb("Add New Tab", New
    EventHandler(AddressOf AddTab))
    verbShowNextTab = New DesignerVerb("Show Next Tab", New
    EventHandler(AddressOf ShowNextTab))
    verbRemoveTab = New DesignerVerb("Remove Current Tab", New
    EventHandler(AddressOf RemoveTab))
    MyBase.Verbs.Add(verbAddTab)
    MyBase.Verbs.Add(verbShowNextTab)
    MyBase.Verbs.Add(verbRemoveTab)
    End Sub 'New

    Public Overrides Sub Initialize(ByVal component As IComponent)
    MyBase.Initialize(component)
    Dim tabStrip As tabStrip = CType(component, tabStrip)
    DesignTimeSelectedIndex = tabStrip.SelectedIndex
    Dim ss As ISelectionService =
    CType(GetService(GetType(ISelectionService)), ISelectionService)
    Dim ccs As IComponentChangeService =
    CType(GetService(GetType(IComponentChangeService)),
    IComponentChangeService)
    If Not (ss Is Nothing) Then
    AddHandler ss.SelectionChanged, AddressOf
    OnSelectionChanged
    AddHandler ccs.ComponentChanged, AddressOf
    OnComponentChanged
    End If
    End Sub 'Initialize

    Protected Overloads Overrides Sub Dispose(ByVal disposing As
    Boolean)
    Dim ss As ISelectionService =
    CType(GetService(GetType(ISelectionService)), ISelectionService)
    Dim ccs As IComponentChangeService =
    CType(GetService(GetType(IComponentChangeService)),
    IComponentChangeService)
    If Not (ss Is Nothing) Then
    AddHandler ss.SelectionChanged, New EventHandler(AddressOf
    OnSelectionChanged)
    AddHandler ccs.ComponentChanged, New
    ComponentChangedEventHandler(AddressOf OnComponentChanged)
    End If
    MyBase.Dispose(disposing)
    End Sub 'Dispose

    Public Overrides Sub OnComponentChanged(ByVal sender As Object,
    ByVal e As ComponentChangedEventArgs)
    MyBase.OnComponentChanged(sender, e)
    If e.Component Is Me.Component Then
    ModifyMenu()
    End If
    End Sub 'OnComponentChanged

    Public Overrides ReadOnly Property
    DesignTimeHtmlRequiresLoadComplete() As Boolean
    Get
    Return True
    End Get
    End Property 'DesignTimeHtmlRequiresLoadComplete

    Protected Overrides Function GetEmptyDesignTimeHtml() As String
    ' Provide the developer with info on how to add tabs to the
    TabControl.
    Dim strHtml As String = ""
    strHtml += "<table style='font-family: Tahoma; font-size: 8pt;
    color:buttontext; background-color:buttonface; border: solid 1px
    border-top-color: buttonhighlight; border-left-color: buttonhightlight;
    border-right-color: buttonshadow; borderbottom-color: buttonshadow'>"
    strHtml += "<tr><td><b>TabStrip</b> - " + Me.ID + "</td></tr>"
    strHtml += "<tr><td>Please add Tabs through the Tabs
    (Collection) property in the Properties pane,</td></tr>"
    strHtml += "<tr><td>or by clicking ""Add New Tab"" in either
    the description area of the</td></tr>"
    strHtml += "<tr><td>Properties pane or the right-click
    menu.</td></tr>"
    strHtml += "<tr><td>Then switch to HTML view and edit each
    Tab's view by inserting inner content.</td></tr></table>"
    Return strHtml
    End Function 'GetEmptyDesignTimeHtml

    Public Overrides Function GetDesignTimeHtml() As String

    Dim tabStrip As tabStrip = CType(Me.Component, tabStrip)
    If Not (tabStrip Is Nothing) And tabStrip.Tabs.Count > 0 Then
    Dim stringWriter As New stringWriter
    Dim writer As New HtmlTextWriter(stringWriter)

    Dim _tabRows As Integer
    Dim _fullRows As Integer
    Dim _tabsInFullRow As Integer = tabStrip.TabsPerRow
    Dim _tabsInPartRow As Integer
    Dim _partRowTabWidth As Unit
    Dim _fullRowTabWidth As Unit
    Dim _fullRowRemainder As Integer
    Dim _partRowRemainder As Integer
    Dim _tabPageHeight As Unit
    Dim _rowArray As Pair()()
    Dim _tabIdx As Integer
    Dim _selectedRow As Integer
    Dim _autoPostBack As Boolean = tabStrip.AutoPostBack
    Dim _tabHeight As Unit = tabStrip.TabHeight
    Dim _width As Unit = tabStrip.Width
    Dim _height As Unit = tabStrip.Height
    Dim _tabCount As Integer = tabStrip.Tabs.Count

    'get the widths of tabs in a full row
    _fullRowTabWidth = Unit.Pixel(Math.Floor(_width.Value /
    CDbl(_tabsInFullRow)))

    'get the number of rows, total
    _tabRows = CType(Math.Ceiling(CDbl(_tabCount) /
    CDbl(_tabsInFullRow)), Integer)

    'get the number of tabs in a partial row (a row with fewer
    than TabsPerRow tabs)
    If _tabRows * _tabsInFullRow = _tabCount Then
    _fullRows = _tabRows
    Else
    _fullRows = _tabRows - 1
    End If
    _tabsInPartRow = _tabCount - (_fullRows * _tabsInFullRow)

    'get the widths of tabs in a partial row
    If _tabsInPartRow > 0 Then
    _partRowTabWidth = Unit.Pixel(Math.Floor(_width.Value /
    CDbl(_tabsInPartRow)))
    Else
    _partRowTabWidth = _fullRowTabWidth
    End If

    'but just in case they don't divide roundly, we need the
    remainders
    _fullRowRemainder = _width.Value - _fullRowTabWidth.Value *
    _tabsInFullRow
    _partRowRemainder = _width.Value - _partRowTabWidth.Value *
    _tabsInPartRow

    'figure out the height of the masterPage
    _tabPageHeight = Unit.Pixel(_height.Value - (_tabRows *
    _tabHeight.Value))

    'let's make a jagged array that represents the tabs in
    their rows
    'we'll put the tab widths in Pair.Second
    ReDim _rowArray(_tabRows - 1)
    For i As Integer = 0 To _tabRows - 1
    If _fullRows < _tabRows And i = 0 Then
    ReDim _rowArray(i)(_tabsInPartRow - 1)
    For j As Integer = 0 To _tabsInPartRow - 1
    If j = 0 Then
    'add in the remainder
    _rowArray(i)(j) = New Pair(-1,
    Unit.Pixel(_partRowTabWidth.Value + _partRowRemainder))
    Else
    _rowArray(i)(j) = New Pair(-1,
    _partRowTabWidth)
    End If
    Next
    Else
    ReDim _rowArray(i)(_tabsInFullRow - 1)
    For j As Integer = 0 To _tabsInFullRow - 1
    If j = 0 Then
    'add in the remainder
    _rowArray(i)(j) = New Pair(-1,
    Unit.Pixel(_fullRowTabWidth.Value + _fullRowRemainder))
    Else
    _rowArray(i)(j) = New Pair(-1,
    _fullRowTabWidth)
    End If
    Next
    End If
    Next

    'now let's fill that array with tab indices (that goes into
    Pair.First)
    Dim _tabCollectionCounter As Integer = 0
    Dim _tabCounter As Integer = 0
    Dim _rowCounter As Integer = _tabRows - 1

    Do While _tabCollectionCounter < _tabCount
    If tabStrip.Tabs(_tabCollectionCounter).Visible Then
    _rowArray(_rowCounter)(_tabCounter).First =
    _tabCollectionCounter
    If _tabCollectionCounter = DesignTimeSelectedIndex
    Then
    _selectedRow = _rowCounter
    End If
    _tabCounter = _tabCounter + 1
    If _tabCounter = _tabsInFullRow Then
    _rowCounter = _rowCounter - 1
    _tabCounter = 0
    End If
    End If
    _tabCollectionCounter = _tabCollectionCounter + 1
    Loop

    'now let's do the rendering
    writer.AddAttribute(HtmlTextWriterAttribute.Cellpadding,
    "0", False)
    writer.AddAttribute(HtmlTextWriterAttribute.Cellspacing,
    "0", False)
    writer.AddAttribute(HtmlTextWriterAttribute.Border, "0",
    False)
    writer.AddAttribute(HtmlTextWriterAttribute.Width,
    _width.ToString, False)
    writer.RenderBeginTag(HtmlTextWriterTag.Table)

    'first do all the rows other than the selected row
    For i As Integer = 0 To _rowArray.GetUpperBound(0)
    If Not i = _selectedRow Then
    writer.RenderBeginTag(HtmlTextWriterTag.Tr)

    writer.AddAttribute(HtmlTextWriterAttribute.Nowrap,
    "true", False)
    writer.AddAttribute(HtmlTextWriterAttribute.Valign,
    "middle", False)
    writer.RenderBeginTag(HtmlTextWriterTag.Td)

    For j As Integer = 0 To
    _rowArray(i).getUpperBound(0)
    _tabIdx = CInt(_rowArray(i)(j).First)
    writer.AddStyleAttribute("border-bottom",
    "none")
    writer.AddStyleAttribute("height",
    _tabHeight.Value.ToString)
    writer.AddStyleAttribute("overflow", "hidden")
    writer.AddStyleAttribute("text-align",
    "center")
    writer.AddStyleAttribute("font-family",
    "system")
    writer.AddStyleAttribute("font-size", "8pt")
    writer.AddStyleAttribute("display", "inline")
    writer.AddStyleAttribute("padding-top", "3px")
    writer.AddStyleAttribute("border-left", "3px
    outset")
    writer.AddStyleAttribute("border-top", "3px
    outset")
    writer.AddStyleAttribute("border-right", "3px
    outset")
    writer.AddStyleAttribute("cursor", "hand")

    writer.AddStyleAttribute(HtmlTextWriterStyle.Width,
    CType(_rowArray(i)(j).Second, Unit).ToString)

    writer.AddStyleAttribute(HtmlTextWriterStyle.Color,
    tabStrip.Tabs(_tabIdx).ForeColor.Name)

    writer.AddStyleAttribute(HtmlTextWriterStyle.BackgroundColor,
    tabStrip.Tabs(_tabIdx).BackColor.Name)

    writer.RenderBeginTag(HtmlTextWriterTag.Div)
    writer.Write(tabStrip.Tabs(_tabIdx).Text)
    writer.RenderEndTag() 'Div
    Next

    writer.RenderEndTag() 'Td
    writer.RenderEndTag() 'Tr
    End If
    Next

    'then do the selected row
    writer.RenderBeginTag(HtmlTextWriterTag.Tr)

    writer.AddAttribute(HtmlTextWriterAttribute.Nowrap, "true",
    False)
    writer.AddAttribute(HtmlTextWriterAttribute.Valign,
    "middle", False)
    writer.RenderBeginTag(HtmlTextWriterTag.Td)

    For j As Integer = 0 To
    _rowArray(_selectedRow).GetUpperBound(0)
    _tabIdx = CInt(_rowArray(_selectedRow)(j).First)
    If _rowArray(_selectedRow)(j).First =
    DesignTimeSelectedIndex Then
    writer.AddStyleAttribute("border-bottom", "none")
    Else
    writer.AddStyleAttribute("border-bottom", "3px
    inset")
    End If
    writer.AddStyleAttribute("height",
    _tabHeight.Value.ToString)
    writer.AddStyleAttribute("overflow", "hidden")
    writer.AddStyleAttribute("text-align", "center")
    writer.AddStyleAttribute("font-family", "system")
    writer.AddStyleAttribute("font-size", "8pt")
    writer.AddStyleAttribute("display", "inline")
    writer.AddStyleAttribute("padding-top", "3px")
    writer.AddStyleAttribute("border-left", "3px outset")
    writer.AddStyleAttribute("border-top", "3px outset")
    writer.AddStyleAttribute("border-right", "3px outset")
    writer.AddStyleAttribute("cursor", "hand")
    writer.AddStyleAttribute(HtmlTextWriterStyle.Width,
    CType(_rowArray(_selectedRow)(j).Second, Unit).ToString)
    writer.AddStyleAttribute(HtmlTextWriterStyle.Color,
    tabStrip.Tabs(_tabIdx).ForeColor.Name)

    writer.AddStyleAttribute(HtmlTextWriterStyle.BackgroundColor,
    tabStrip.Tabs(_tabIdx).BackColor.Name)

    writer.RenderBeginTag(HtmlTextWriterTag.Div)
    writer.Write(tabStrip.Tabs(_tabIdx).Text)
    writer.RenderEndTag() 'Div
    Next

    writer.RenderEndTag() 'Td
    writer.RenderEndTag() 'Tr

    'so much for the tabs. Now the tab pages/panels
    writer.RenderBeginTag(HtmlTextWriterTag.Tr)
    writer.RenderBeginTag(HtmlTextWriterTag.Td)


    writer.AddStyleAttribute(HtmlTextWriterStyle.BackgroundColor,
    tabStrip.Tabs(tabStrip.SelectedIndex).BackColor.Name)
    writer.AddStyleAttribute("overflow", "auto")
    writer.AddStyleAttribute("border-left", "3px outset")
    writer.AddStyleAttribute("border-bottom", "3px outset")
    writer.AddStyleAttribute("border-right", "3px outset")
    writer.AddStyleAttribute("display", "inline")
    writer.AddStyleAttribute(HtmlTextWriterStyle.Height,
    _tabPageHeight.ToString)
    writer.AddStyleAttribute(HtmlTextWriterStyle.Width,
    _width.ToString)
    writer.RenderBeginTag(HtmlTextWriterTag.Div)

    For Each myTab As Tab In tabStrip.Tabs
    ' Only render the TabView under the following
    conditions:
    ' (1) AutoPostBack is set to false.
    ' (2) AutoPostBack is set to true, and the TabView is
    for the Selected Tab
    If DesignTimeSelectedIndex =
    tabStrip.Tabs.IndexOf(myTab) Then
    writer.AddStyleAttribute(HtmlTextWriterStyle.Width,
    myTab.InnerWidth.ToString)

    writer.AddStyleAttribute(HtmlTextWriterStyle.Height,
    myTab.InnerHeight.ToString)

    writer.AddStyleAttribute(HtmlTextWriterStyle.BackgroundColor,
    myTab.BackColor.Name)
    writer.AddStyleAttribute(HtmlTextWriterStyle.Color,
    myTab.ForeColor.Name)
    writer.AddStyleAttribute("text-align", "center")
    writer.RenderBeginTag(HtmlTextWriterTag.Div)

    If myTab.HasControls() = False Then
    myTab.Controls.Add(New
    LiteralControl("&nbsp;"))
    End If

    For Each myControl As Control In myTab.Controls
    myControl.RenderControl(writer)
    Next

    writer.RenderEndTag() 'Div
    End If
    Next

    writer.RenderEndTag() 'Div
    writer.RenderEndTag() 'Td
    writer.RenderEndTag() 'Tr
    writer.RenderEndTag() 'Table

    Return stringWriter.ToString()
    Else
    Return Me.GetEmptyDesignTimeHtml()
    End If

    End Function 'GetDesignTimeHtml

    Private Sub OnSelectionChanged(ByVal sender As Object, ByVal e As
    EventArgs)
    Dim ss As ISelectionService = CType(sender, ISelectionService)
    If Not (ss Is Nothing) Then
    Dim bTabControlSelected As Boolean =
    ss.GetComponentSelected(Me.Component)
    If bTabControlSelected Then
    ModifyMenu()
    End If
    End If
    End Sub 'OnSelectionChanged

    Private Sub ModifyMenu()
    Dim tabStrip As tabStrip = CType(Me.Component, tabStrip)
    verbShowNextTab.Visible = False
    verbRemoveTab.Visible = False
    verbShowNextTab.Visible = tabStrip.Tabs.Count > 1
    verbRemoveTab.Visible = tabStrip.Tabs.Count > 0
    End Sub 'ModifyMenu

    Private Sub AddTab(ByVal sender As Object, ByVal e As EventArgs)
    Dim tabStrip As tabStrip = CType(Me.Component, tabStrip)
    Dim myTab As New Tab
    tabStrip.Tabs.Add(myTab)
    tabStrip.Controls.Add(myTab)
    myTab.Text = "Tab " & tabStrip.Tabs.Count.ToString
    myTab.ID = myTab.ClientID
    DesignTimeSelectedIndex = tabStrip.Tabs.Count - 1
    OnComponentChanged(Me, New ComponentChangedEventArgs(tabStrip,
    Nothing, Nothing, Nothing))
    End Sub 'AddTab

    Private Sub ShowNextTab(ByVal sender As Object, ByVal e As
    EventArgs)
    Dim tabStrip As tabStrip = CType(Me.Component, tabStrip)
    Dim TabCount As Integer = tabStrip.Tabs.Count
    If TabCount > 0 Then
    DesignTimeSelectedIndex = (DesignTimeSelectedIndex + 1) Mod
    TabCount
    UpdateDesignTimeHtml()
    End If
    End Sub 'ShowNextTab

    Private Sub RemoveTab(ByVal sender As Object, ByVal e As EventArgs)
    Dim tabStrip As tabStrip = CType(Me.Component, tabStrip)
    If tabStrip.Tabs.Count > 0 Then
    tabStrip.Tabs.RemoveAt(DesignTimeSelectedIndex)
    ' Ensure the selected index is still valid.
    ' It is possible that the selected Tab was the last one,
    ' and that one was removed.
    If tabStrip.SelectedIndex >= tabStrip.Tabs.Count Then
    tabStrip.SelectedIndex = tabStrip.Tabs.Count - 1
    If tabStrip.SelectedIndex < 0 Then
    tabStrip.SelectedIndex = 0
    End If
    End If
    ' Commit the Change
    OnComponentChanged(Me, New
    ComponentChangedEventArgs(tabStrip, Nothing, Nothing, Nothing))
    ' Show the closest, right-most sibling Tab in the Designer
    DesignTimeSelectedIndex -= 1
    If DesignTimeSelectedIndex + 1 >= tabStrip.Tabs.Count Then
    DesignTimeSelectedIndex -= 1
    End If
    ShowNextTab(Me, EventArgs.Empty)
    End If
    End Sub 'RemoveTab

    End Class 'TabControlDesigner
    , Apr 29, 2005
    #1
    1. Advertising

  2. Guest

    I figured out what to do to fix my problem, but I don't understand why
    it was causing the problem to begin with. I changed the New method for
    the Tab so that it doesn't take any arguments. And now it works. Go
    figure. I guess I can live with the mystery, so long as the control is
    working.

    I made some other tweaks, because there were some minor bugs I hadn't
    found. If anyone wants a copy of the control, let me know and I'll
    either post it or put it up on my site so that you can download it.

    Once I'm totally satisfied with it, I think I'm going to add remote
    scripting capability, so that it can autopostback without the page
    blinking. They deprecated the blink tag, but .NET is still giving us
    eyeaches. That's got to go.

    Lisa


    wrote:
    > I really, really wanted to finish this one without asking anyone for
    > help. But I've been beating my head against this thing, and I'm
    > getting nowhere.
    >
    > I wrote a tab control. I cribbed some ideas from the BlueValley one,
    > but mostly after I'd finished the main stuff.
    >
    > It works just great in design time (the opposite of the usual

    problem).
    > Except that if I try to add any content to any of the tabs in the

    HTML
    > view, when I go back to design view, the control won't render

    anymore.
    > The same thing happens if I try adding content to a tab
    > programmatically. At least I think. The problem with knowing for

    sure
    > is that if I try to view a page that has a tab control on it, whether

    I
    > add content or not, the same thing happens, and I get an error.
    >
    > When I trace the error, I find that either running the page or adding
    > content in HTML view or both causes the tabs collection to evaporate
    > into Nothing.
    >
    > I've tried debugging in every way I can, but I can't figure out

    what's
    > making the collection not persist. I'm posting the code here. Feel
    > free to take it and use it for yourself, if it becomes fixable. But

    if
    > anyone can tell me what I'm doing wrong, I'd very much appreciate it.
    >
    > Um... it's IE only. Again. Sorry.
    >
    > TIA,
    > Lisa
    >
    > Imports System.ComponentModel
    > Imports System.ComponentModel.Design
    > Imports System.Web.UI
    > Imports System.IO
    > Imports System.Web.UI.WebControls
    > Imports System.Web.UI.HtmlControls
    >
    > <ToolboxData("<{0}:TabStrip runat=server></{0}:TabStrip>"),
    > Designer(GetType(TabStripDesigner)), PersistChildren(False),
    > ParseChildren(True, "Tabs"), DefaultProperty("Tabs"),
    > DefaultEvent("SelectedIndexChanged")> _
    > Public Class TabStrip
    > Inherits WebControl
    > Implements INamingContainer, IPostBackDataHandler,
    > IPostBackEventHandler
    >
    > Private _tabs As New TabCollection
    > Private _tabsPerRow As Integer = 3
    > Private _tabHeight As New Unit(25, UnitType.Pixel)
    > Private _width As New Unit(300, UnitType.Pixel)
    > Private _height As New Unit(250, UnitType.Pixel)
    > Private _selectedIndex As Integer = 0
    > Private _autoPostBack As Boolean = False
    > Private _tabCount As Integer
    >
    > Private _tabRows As Integer
    > Private _fullRows As Integer
    > Private _tabsInPartRow As Integer
    > Private _tabsInFullRow As Integer
    > Private _fullRowTabWidth As Unit
    > Private _partRowTabWidth As Unit
    > Private _fullRowRemainder As Integer
    > Private _partRowRemainder As Integer
    > Private _tabPageHeight As Unit
    > Private _visibleTabs As Integer
    > Private _rowArray As Pair()()
    > Private _selectedRow As Integer
    > Private _tabIdx As Integer
    > Private _firstVisibleTabIdx As Integer = -1
    >
    > <Category("Behavior"), Description("The collection of tabs."),
    >

    DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
    > NotifyParentProperty(True),
    > PersistenceMode(PersistenceMode.InnerDefaultProperty)> _
    > Public ReadOnly Property Tabs() As TabCollection
    > Get
    > Return _tabs
    > End Get
    > End Property
    >
    > <Category("Appearance"), Description("The maximum number of tabs

    in
    > a row."),
    >

    DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
    > NotifyParentProperty(True),

    PersistenceMode(PersistenceMode.Attribute)>
    > _
    > Public Property TabsPerRow() As Integer
    > Get
    > Return _tabsPerRow
    > End Get
    > Set(ByVal Value As Integer)
    > _tabsPerRow = Value
    > End Set
    > End Property 'TabsPerRow
    >
    > <Category("Appearance"), Description("The height of each tab
    > row.")> _
    > Public Property TabHeight() As Unit
    > Get
    > Return _tabHeight
    > End Get
    > Set(ByVal Value As Unit)
    > If Not Value.Type = UnitType.Pixel Then
    > Throw New ArgumentException("TabHeight must be given

    in
    > pixels.")
    > End If
    > _tabHeight = Value
    > End Set
    > End Property 'TabHeight
    >
    > <Category("Appearance"), Description("The width of the

    control.")>
    > _
    > Public Overrides Property Width() As Unit
    > Get
    > Return _width
    > End Get
    > Set(ByVal Value As Unit)
    > If Not Value.Type = UnitType.Pixel Then
    > Throw New ArgumentException("Width must be given in
    > pixels.")
    > End If
    > _width = Value
    > End Set
    > End Property 'Width
    >
    > <Category("Appearance"), Description("The height of the

    control.")>
    > _
    > Public Overrides Property Height() As Unit
    > Get
    > Return _height
    > End Get
    > Set(ByVal Value As Unit)
    > If Not Value.Type = UnitType.Pixel Then
    > Throw New ArgumentException("Height must be given in
    > pixels.")
    > End If
    > _height = Value
    > End Set
    > End Property 'Height
    >
    > <Browsable(False)> _
    > Public Property SelectedIndex() As Integer
    > Get
    > Return _selectedIndex
    > End Get
    > Set(ByVal Value As Integer)
    > _selectedIndex = Value
    > End Set
    > End Property
    >
    > <DefaultValue(True)> _
    > Public Property AutoPostBack() As Boolean
    > Get
    > Return _autoPostBack
    > End Get
    > Set(ByVal Value As Boolean)
    > _autoPostBack = Value
    > End Set
    > End Property
    >
    > Protected Overrides Sub OnInit(ByVal e As EventArgs)
    > MyBase.OnInit(e)
    > If AutoPostBack And Not (Page Is Nothing) Then
    > Page.RegisterRequiresPostBack(Me)
    > End If
    > End Sub 'OnInit
    >
    > Protected Overrides Sub LoadViewState(ByVal viewState As Object)
    > If Not (viewState Is Nothing) And _autoPostBack Then
    > _selectedIndex = Int32.Parse(CType(viewState, String))
    > Else
    > MyBase.LoadViewState(viewState)
    > End If
    > End Sub 'LoadViewState
    >
    > Protected Overrides Function SaveViewState() As Object
    > ' If AutoPostBack is set, save the SelectedTab to the view
    > state for postback scenarios
    > If _autoPostBack Then
    > Return _selectedIndex.ToString()
    > Else
    > Return MyBase.SaveViewState()
    > End If
    > End Function 'SaveViewState
    >
    > #Region "Overriden methods"
    >
    > Protected Overrides Sub OnPreRender(ByVal e As System.EventArgs)
    >
    > 'this script is client script and should appear only once
    > If Not Page.IsClientScriptBlockRegistered("TabStrip_vbs")

    Then
    > Dim reader As New
    >

    System.IO.StreamReader(Me.GetType().Assembly.GetManifestResourceStream(Me.GetType(),
    > "TabStrip.vbs"))
    > Dim script As String = "<script language='vbscript'
    > type='text/vbscript' >" _
    > + ControlChars.CrLf _
    > + "<!--" _
    > + ControlChars.CrLf _
    > + reader.ReadToEnd() _
    > + ControlChars.CrLf _
    > + "//-->" _
    > + ControlChars.CrLf _
    > + "</script>"
    > Page.RegisterClientScriptBlock("TabStrip_vbs", script)
    >
    > reader = Nothing
    > script = Nothing
    > End If
    >
    > End Sub 'OnPreRender
    >
    > Private Function GetSelectedIndexForRender() As Integer
    >
    > If Tabs.Count > 0 Then
    > ' Get the Selected Index.
    > ' For a non-AutoPostBack TabControl, the selected index
    > ' is stored in a cookie.
    > ' Otherwise, it is stored as a property of the

    TabControl.
    > If Not _autoPostBack And Not (Page Is Nothing) Then
    > _selectedIndex = 0
    > Dim cookie As System.Web.HttpCookie =
    > Page.Request.Cookies((Me.UniqueID + "_SelectedIndex"))
    > If Not (cookie Is Nothing) Then
    > _selectedIndex = Int32.Parse(cookie.Value)
    > End If
    > If _selectedIndex < 0 Or _selectedIndex > _tabCount -

    1
    > Then
    > _selectedIndex = 0
    > End If
    > End If
    >
    > 'if the selected tab isn't visible and enabled, it can't

    be
    > selected
    > If Tabs(_selectedIndex).Visible And
    > Tabs(_selectedIndex).Enabled Then
    > Return _selectedIndex
    > Else
    > _selectedIndex = -1
    > 'get the first tab that's both visible and enabled

    and
    > select it
    > For Each myTab As Tab In Tabs
    > If myTab.Visible And myTab.Enabled Then
    > Return Tabs.IndexOf(myTab)
    > Exit For
    > End If
    > Next
    > End If
    > End If
    >
    > End Function 'GetSelectedIndexForRender
    >
    > Private Sub GetTabFormatValuesForRender()
    >
    > 'get the number of tabs in full rows and their widths
    > _tabsInFullRow = TabsPerRow
    > _fullRowTabWidth = Unit.Pixel(Math.Floor(Width.Value /
    > CDbl(_tabsInFullRow)))
    >
    > 'get the number of rows, total
    > _tabRows = CType(Math.Ceiling(CDbl(_visibleTabs) /
    > CDbl(_tabsInFullRow)), Integer)
    >
    > 'get the number of tabs in a partial row (a row with fewer

    than
    > TabsPerRow tabs)
    > If _tabRows * _tabsInFullRow = _visibleTabs Then
    > _fullRows = _tabRows
    > Else
    > _fullRows = _tabRows - 1
    > End If
    > _tabsInPartRow = _visibleTabs - (_fullRows * _tabsInFullRow)
    >
    > 'get the widths of tabs in a partial row
    > If _tabsInPartRow > 0 Then
    > _partRowTabWidth = Unit.Pixel(Math.Floor(Width.Value /
    > CDbl(_tabsInPartRow)))
    > Else
    > _partRowTabWidth = _fullRowTabWidth
    > End If
    >
    > 'but just in case they don't divide roundly, we need the
    > remainders
    > _fullRowRemainder = Width.Value - _fullRowTabWidth.Value *
    > _tabsInFullRow
    > _partRowRemainder = Width.Value - _partRowTabWidth.Value *
    > _tabsInPartRow
    >
    > 'figure out the height of the masterPage
    > _tabPageHeight = Unit.Pixel(Height.Value - (_tabRows *
    > TabHeight.Value))
    >
    > 'let's make a jagged array that represents the tabs in their
    > rows
    > 'we'll put the tab widths in Pair.Second
    > ReDim _rowArray(_tabRows - 1)
    > For i As Integer = 0 To _tabRows - 1
    > If _fullRows < _tabRows And i = 0 Then
    > ReDim _rowArray(i)(_tabsInPartRow - 1)
    > For j As Integer = 0 To _tabsInPartRow - 1
    > If j = 0 Then
    > 'add in the remainder
    > _rowArray(i)(j) = New Pair(-1,
    > Unit.Pixel(_partRowTabWidth.Value + _partRowRemainder))
    > Else
    > _rowArray(i)(j) = New Pair(-1,
    > _partRowTabWidth)
    > End If
    > Next
    > Else
    > ReDim _rowArray(i)(_tabsInFullRow - 1)
    > For j As Integer = 0 To _tabsInFullRow - 1
    > If j = 0 Then
    > 'add in the remainder
    > _rowArray(i)(j) = New Pair(-1,
    > Unit.Pixel(_fullRowTabWidth.Value + _fullRowRemainder))
    > Else
    > _rowArray(i)(j) = New Pair(-1,
    > _fullRowTabWidth)
    > End If
    > Next
    > End If
    > Next
    >
    > 'now let's fill that array with tab indices (that goes into
    > Pair.First)
    > Dim _tabCollectionCounter As Integer = 0
    > Dim _tabCounter As Integer = 0
    > Dim _rowCounter As Integer = _tabRows - 1
    >
    > Do While _tabCollectionCounter < _tabCount
    > If Tabs(_tabCollectionCounter).Visible Then
    > _rowArray(_rowCounter)(_tabCounter).First =
    > _tabCollectionCounter
    > If _tabCollectionCounter = _selectedIndex Then
    > _selectedRow = _rowCounter
    > End If
    > _tabCounter = _tabCounter + 1
    > If _tabCounter = _tabsInFullRow Then
    > _rowCounter = _rowCounter - 1
    > _tabCounter = 0
    > End If
    > End If
    > _tabCollectionCounter = _tabCollectionCounter + 1
    > Loop
    >
    > End Sub 'GetTabFormatValuesForRender
    >
    > Protected Overrides Sub Render(ByVal writer As
    > System.Web.UI.HtmlTextWriter)
    >
    > 'get the number of visible tabs
    > _visibleTabs = 0
    > For Each myTab As Tab In Tabs
    > If myTab.Visible Then
    > _visibleTabs = _visibleTabs + 1
    > End If
    > Next
    >
    > 'if there are no visible tabs, don't render the control
    > If _visibleTabs = 0 Then
    > Exit Sub
    > End If
    >
    > 'if there is no usable selectedindex, don't render the

    control
    > If GetSelectedIndexForRender() = -1 Then
    > Exit Sub
    > End If
    >
    > 'get the arrangement and width of tabs
    > GetTabFormatValuesForRender()
    >
    > 'now let's do the rendering
    > writer.AddAttribute(HtmlTextWriterAttribute.Cellpadding, "0",
    > False)
    > writer.AddAttribute(HtmlTextWriterAttribute.Cellspacing, "0",
    > False)
    > writer.AddAttribute(HtmlTextWriterAttribute.Border, "0",

    False)
    > writer.AddAttribute(HtmlTextWriterAttribute.Width,
    > Width.ToString, False)
    > writer.RenderBeginTag(HtmlTextWriterTag.Table)
    >
    > 'first do the rows other than the selected row
    > For i As Integer = 0 To _rowArray.GetUpperBound(0)
    > If Not i = _selectedRow Then
    > writer.RenderBeginTag(HtmlTextWriterTag.Tr)
    >
    > writer.AddAttribute(HtmlTextWriterAttribute.Nowrap,
    > "true", False)
    > writer.AddAttribute(HtmlTextWriterAttribute.Valign,
    > "middle", False)
    > writer.RenderBeginTag(HtmlTextWriterTag.Td)
    >
    > For j As Integer = 0 To _rowArray(i).GetUpperBound(0)
    > _tabIdx = CInt(_rowArray(i)(j).First)
    > writer.AddStyleAttribute("border-bottom", "none")
    > writer.AddStyleAttribute("height",
    > TabHeight.Value.ToString)
    > writer.AddStyleAttribute("overflow", "hidden")
    > writer.AddStyleAttribute("text-align", "center")
    > writer.AddStyleAttribute("font-family", "system")
    > writer.AddStyleAttribute("font-size", "8pt")
    > writer.AddStyleAttribute("display", "inline")
    > writer.AddStyleAttribute("padding-top", "3px")
    > writer.AddStyleAttribute("border-left", "3px
    > outset")
    > writer.AddStyleAttribute("border-top", "3px
    > outset")
    > writer.AddStyleAttribute("border-right", "3px
    > outset")
    > writer.AddStyleAttribute("cursor", "hand")
    >

    writer.AddStyleAttribute(HtmlTextWriterStyle.Width,
    > CType(_rowArray(i)(j).Second, Unit).ToString)
    >

    writer.AddStyleAttribute(HtmlTextWriterStyle.Color,
    > Tabs(_tabIdx).ForeColor.Name)
    >
    > writer.AddStyleAttribute(HtmlTextWriterStyle.BackgroundColor,
    > Tabs(_tabIdx).BackColor.Name)
    > 'set the onclick depending on whether

    AutoPostBack
    > is true or not
    > If _autoPostBack Then
    >
    > writer.AddAttribute(HtmlTextWriterAttribute.Onclick, "jscript:" +
    > Page.GetPostBackEventReference(Me, _tabIdx.ToString()), False)
    > Else
    >
    > writer.AddAttribute(HtmlTextWriterAttribute.Onclick,
    > "TabStrip_SelectTab(this)", False)
    > End If
    > writer.AddAttribute(HtmlTextWriterAttribute.Name,
    > "tab_" & _tabIdx.ToString, False)
    > writer.AddAttribute(HtmlTextWriterAttribute.Id,
    > "tab_" & _tabIdx.ToString, False)
    >
    > writer.RenderBeginTag(HtmlTextWriterTag.Div)
    > writer.Write(Tabs(_tabIdx).Text)
    > writer.RenderEndTag() 'Div
    > Next
    >
    > writer.RenderEndTag() 'Td
    > writer.RenderEndTag() 'Tr
    > End If
    > Next
    >
    > 'now do the selected row
    > writer.RenderBeginTag(HtmlTextWriterTag.Tr)
    >
    > writer.AddAttribute(HtmlTextWriterAttribute.Nowrap, "true",
    > False)
    > writer.AddAttribute(HtmlTextWriterAttribute.Valign, "middle",
    > False)
    > writer.RenderBeginTag(HtmlTextWriterTag.Td)
    >
    > For j As Integer = 0 To
    > _rowArray(_selectedRow).GetUpperBound(0)
    > _tabIdx = CInt(_rowArray(_selectedRow)(j).First)
    > If _rowArray(_selectedRow)(j).First = _selectedIndex Then
    > writer.AddStyleAttribute("border-bottom", "none")
    > Else
    > writer.AddStyleAttribute("border-bottom", "3px

    inset")
    > End If
    > writer.AddStyleAttribute("height",
    > TabHeight.Value.ToString)
    > writer.AddStyleAttribute("overflow", "hidden")
    > writer.AddStyleAttribute("text-align", "center")
    > writer.AddStyleAttribute("font-family", "system")
    > writer.AddStyleAttribute("font-size", "8pt")
    > writer.AddStyleAttribute("display", "inline")
    > writer.AddStyleAttribute("padding-top", "3px")
    > writer.AddStyleAttribute("border-left", "3px outset")
    > writer.AddStyleAttribute("border-top", "3px outset")
    > writer.AddStyleAttribute("border-right", "3px outset")
    > writer.AddStyleAttribute("cursor", "hand")
    > writer.AddStyleAttribute(HtmlTextWriterStyle.Width,
    > CType(_rowArray(_selectedRow)(j).Second, Unit).ToString)
    > writer.AddStyleAttribute(HtmlTextWriterStyle.Color,
    > Tabs(_tabIdx).ForeColor.Name)
    >
    > writer.AddStyleAttribute(HtmlTextWriterStyle.BackgroundColor,
    > Tabs(_tabIdx).BackColor.Name)
    > 'set the onclick depending on whether AutoPostBack is

    true
    > or not
    > If _autoPostBack Then
    > writer.AddAttribute(HtmlTextWriterAttribute.Onclick,
    > "jscript:" + Page.GetPostBackEventReference(Me, _tabIdx.ToString()),
    > False)
    > Else
    > writer.AddAttribute(HtmlTextWriterAttribute.Onclick,
    > "TabStrip_SelectTab(this)", False)
    > End If
    > writer.AddAttribute(HtmlTextWriterAttribute.Name, "tab_"

    &
    > _tabIdx.ToString, False)
    > writer.AddAttribute(HtmlTextWriterAttribute.Id, "tab_" &
    > _tabIdx.ToString, False)
    > writer.RenderBeginTag(HtmlTextWriterTag.Div)
    > writer.Write(Tabs(_tabIdx).Text)
    > writer.RenderEndTag() 'Div
    > Next
    >
    > writer.RenderEndTag() 'Td
    > writer.RenderEndTag() 'Tr
    >
    > 'so much for the tabs. Now the tab pages/panels
    > writer.RenderBeginTag(HtmlTextWriterTag.Tr)
    > writer.RenderBeginTag(HtmlTextWriterTag.Td)
    >
    > writer.AddStyleAttribute(HtmlTextWriterStyle.BackgroundColor,
    > Tabs(_selectedIndex).BackColor.Name)
    > writer.AddStyleAttribute("overflow", "auto")
    > writer.AddStyleAttribute("border-left", "3px outset")
    > writer.AddStyleAttribute("border-bottom", "3px outset")
    > writer.AddStyleAttribute("border-right", "3px outset")
    > writer.AddStyleAttribute("display", "inline")
    > writer.AddStyleAttribute(HtmlTextWriterStyle.Height,
    > _tabPageHeight.ToString)
    > writer.AddStyleAttribute(HtmlTextWriterStyle.Width,
    > Width.ToString)
    > writer.RenderBeginTag(HtmlTextWriterTag.Div)
    >
    > For Each myTab As Tab In Tabs
    > ' Only render the TabView under the following conditions:
    > ' (1) AutoPostBack is set to false.
    > ' (2) AutoPostBack is set to true, and the TabView is for
    > the Selected Tab
    > If Not _autoPostBack Or (_autoPostBack And _selectedIndex

    =
    > _tabs.IndexOf(myTab)) Then
    > writer.AddStyleAttribute(HtmlTextWriterStyle.Width,
    > myTab.InnerWidth.ToString)
    > writer.AddStyleAttribute(HtmlTextWriterStyle.Height,
    > myTab.InnerHeight.ToString)
    >
    > writer.AddStyleAttribute(HtmlTextWriterStyle.BackgroundColor,
    > myTab.BackColor.Name)
    > writer.AddStyleAttribute(HtmlTextWriterStyle.Color,
    > myTab.ForeColor.Name)
    > writer.AddStyleAttribute("text-align", "center")
    > writer.AddAttribute(HtmlTextWriterAttribute.Id,
    > Me.ClientID & "_panel_" & Tabs.IndexOf(myTab).ToString, False)
    > writer.AddAttribute(HtmlTextWriterAttribute.Name,
    > Me.ClientID & "_panel_" & Tabs.IndexOf(myTab).ToString, False)
    > If _selectedIndex = _tabs.IndexOf(myTab) Then
    > writer.AddStyleAttribute("display", "inline")
    > Else
    > writer.AddStyleAttribute("display", "none")
    > End If
    > writer.RenderBeginTag(HtmlTextWriterTag.Div)
    >
    > If myTab.HasControls() = False Then
    > myTab.Controls.Add(New LiteralControl("&nbsp;"))
    > End If
    >
    > For Each myControl As Control In mytab.Controls
    > myControl.RenderControl(writer)
    > Next
    >
    > writer.RenderEndTag() 'Div
    > End If
    > Next
    >
    > writer.RenderEndTag() 'Div
    > writer.RenderEndTag() 'Td
    > writer.RenderEndTag() 'Tr
    > writer.RenderEndTag() 'Table
    >
    > End Sub 'Render
    >
    > #End Region
    >
    > Public Function LoadPostData(ByVal postDataKey As String, ByVal
    > postCollection As System.Collections.Specialized.NameValueCollection)
    > As Boolean Implements System.Web.UI.IPostBackDataHandler.LoadPostData
    > ' Stub Implementation, Required for IPostBackDataHandler
    > ' This control must derive from IPostBackDataHandler, even
    > though it doesn't use its methods.
    > End Function 'LoadPostData
    >
    > Public Sub RaisePostDataChangedEvent() Implements
    > System.Web.UI.IPostBackDataHandler.RaisePostDataChangedEvent
    > ' Stub Implementation, Required for IPostBackDataHandler
    > ' This control must derive from IPostBackDataHandler, even
    > though it doesn't use its methods.
    > End Sub 'RaisePostDataChangedEvent
    >
    > Public Sub RaisePostBackEvent(ByVal eventArgument As String)
    > Implements System.Web.UI.IPostBackEventHandler.RaisePostBackEvent
    > If eventArgument Is Nothing Then
    > Return
    > End If
    > _selectedIndex = Int32.Parse(eventArgument)
    > Dim e As New EventArgs
    > OnSelectedIndexChanged(e)
    > End Sub 'RaisePostBackEvent
    >
    > Public Event SelectedIndexChanged As EventHandler
    >
    > Public Overridable Sub OnSelectedIndexChanged(ByVal e As

    EventArgs)
    > RaiseEvent SelectedIndexChanged(Me, e)
    > End Sub 'OnSelectedIndexChanged
    >
    > End Class 'TabStrip
    >
    > <ToolboxItem(False)> _
    > Public Class Tab
    > Inherits Control
    >
    > Private _text As String
    > Private _innerHeight As Unit
    > Private _innerWidth As Unit
    > Private _enabled As Boolean
    > Private _visible As Boolean
    > Private _foreColor As System.Drawing.Color
    > Private _backColor As System.Drawing.Color
    >
    > Public Sub New(Optional ByVal TabText As String = "Tab")
    > Me.Text = TabText
    > Me.InnerHeight = Unit.Percentage(100)
    > Me.InnerWidth = Unit.Percentage(100)
    > Me.Enabled = True
    > Me.Visible = True
    > Me.ForeColor = System.Drawing.Color.Black
    > Me.BackColor = System.Drawing.Color.Silver
    > End Sub
    >
    > <Browsable(True), Category("Appearance"), Description("The text
    > appearing on the tab.")> _
    > Public Property Text() As String
    > Get
    > Return _text
    > End Get
    > Set(ByVal Value As String)
    > _text = Value
    > End Set
    > End Property 'Text
    >
    > <Browsable(True), Category("Appearance"), Description("The height
    > of the content of the tab panel (can be greater or less than the

    height
    > of the panel itself).")> _
    > Public Property InnerHeight() As Unit
    > Get
    > Return _innerHeight
    > End Get
    > Set(ByVal Value As Unit)
    > _innerHeight = Value
    > End Set
    > End Property 'InnerHeight
    >
    > <Browsable(True), Category("Appearance"), Description("The width

    of
    > the content of the tab panel (can be greater or less than the width

    of
    > the panel itself).")> _
    > Public Property InnerWidth() As Unit
    > Get
    > Return _innerWidth
    > End Get
    > Set(ByVal Value As Unit)
    > _innerWidth = Value
    > End Set
    > End Property 'InnerWidth
    >
    > <Browsable(True), Category("Behavior"), Description("Whether tab
    > can be selected and contents accessed in runtime or not.")> _
    > Public Property Enabled() As Boolean
    > Get
    > Return _enabled
    > End Get
    > Set(ByVal Value As Boolean)
    > _enabled = Value
    > End Set
    > End Property 'Enabled
    >
    > <Browsable(True), Category("Behavior"), Description("Whether tab

    is
    > visible at runtime or not.")> _
    > Public Overrides Property Visible() As Boolean
    > Get
    > Return _visible
    > End Get
    > Set(ByVal Value As Boolean)
    > _visible = Value
    > End Set
    > End Property 'Visible
    >
    > <Browsable(True), Category("Appearance"), Description("The color

    of
    > the text appearing on the tab.")> _
    > Public Property ForeColor() As System.Drawing.Color
    > Get
    > Return _foreColor
    > End Get
    > Set(ByVal Value As System.Drawing.Color)
    > _foreColor = Value
    > End Set
    > End Property 'ForeColor
    >
    > <Browsable(True), Category("Appearance"), Description("The
    > background of the tab.")> _
    > Public Property BackColor() As System.Drawing.Color
    > Get
    > Return _backColor
    > End Get
    > Set(ByVal Value As System.Drawing.Color)
    > _backColor = Value
    > End Set
    > End Property 'BackColor
    >
    > End Class 'Tab
    >
    > Public Class TabCollection
    > Inherits CollectionBase
    >
    > Default Public ReadOnly Property Item(ByVal index As Integer) As
    > Tab
    > Get
    > Return CType(MyBase.List(index), Tab)
    > End Get
    > End Property 'Item
    >
    > Public Sub Add(ByVal myTab As Tab)
    > MyBase.List.Add(myTab)
    > End Sub 'Add
    >
    > Public Function IndexOf(ByVal myTab As Tab) As Integer
    > Return MyBase.List.IndexOf(myTab)
    > End Function 'IndexOf
    >
    > End Class 'TabCollection
    >
    > Public Class TabStripDesigner
    > Inherits System.Web.UI.Design.ControlDesigner
    >
    > Private verbAddTab As DesignerVerb
    > Private verbShowNextTab As DesignerVerb
    > Private verbRemoveTab As DesignerVerb
    > Private DesignTimeSelectedIndex As Integer
    >
    > Public Sub New()
    > verbAddTab = New DesignerVerb("Add New Tab", New
    > EventHandler(AddressOf AddTab))
    > verbShowNextTab = New DesignerVerb("Show Next Tab", New
    > EventHandler(AddressOf ShowNextTab))
    > verbRemoveTab = New DesignerVerb("Remove Current Tab", New
    > EventHandler(AddressOf RemoveTab))
    > MyBase.Verbs.Add(verbAddTab)
    > MyBase.Verbs.Add(verbShowNextTab)
    > MyBase.Verbs.Add(verbRemoveTab)
    > End Sub 'New
    >
    > Public Overrides Sub Initialize(ByVal component As IComponent)
    > MyBase.Initialize(component)
    > Dim tabStrip As tabStrip = CType(component, tabStrip)
    > DesignTimeSelectedIndex = tabStrip.SelectedIndex
    > Dim ss As ISelectionService =
    > CType(GetService(GetType(ISelectionService)), ISelectionService)
    > Dim ccs As IComponentChangeService =
    > CType(GetService(GetType(IComponentChangeService)),
    > IComponentChangeService)
    > If Not (ss Is Nothing) Then
    > AddHandler ss.SelectionChanged, AddressOf
    > OnSelectionChanged
    > AddHandler ccs.ComponentChanged, AddressOf
    > OnComponentChanged
    > End If
    > End Sub 'Initialize
    >
    > Protected Overloads Overrides Sub Dispose(ByVal disposing As
    > Boolean)
    > Dim ss As ISelectionService =
    > CType(GetService(GetType(ISelectionService)), ISelectionService)
    > Dim ccs As IComponentChangeService =
    > CType(GetService(GetType(IComponentChangeService)),
    > IComponentChangeService)
    > If Not (ss Is Nothing) Then
    > AddHandler ss.SelectionChanged, New

    EventHandler(AddressOf
    > OnSelectionChanged)
    > AddHandler ccs.ComponentChanged, New
    > ComponentChangedEventHandler(AddressOf OnComponentChanged)
    > End If
    > MyBase.Dispose(disposing)
    > End Sub 'Dispose
    >
    > Public Overrides Sub OnComponentChanged(ByVal sender As Object,
    > ByVal e As ComponentChangedEventArgs)
    > MyBase.OnComponentChanged(sender, e)
    > If e.Component Is Me.Component Then
    > ModifyMenu()
    > End If
    > End Sub 'OnComponentChanged
    >
    > Public Overrides ReadOnly Property
    > DesignTimeHtmlRequiresLoadComplete() As Boolean
    > Get
    > Return True
    > End Get
    > End Property 'DesignTimeHtmlRequiresLoadComplete
    >
    > Protected Overrides Function GetEmptyDesignTimeHtml() As String
    > ' Provide the developer with info on how to add tabs to the
    > TabControl.
    > Dim strHtml As String = ""
    > strHtml += "<table style='font-family: Tahoma; font-size:

    8pt;
    > color:buttontext; background-color:buttonface; border: solid 1px
    > border-top-color: buttonhighlight; border-left-color:

    buttonhightlight;
    > border-right-color: buttonshadow; borderbottom-color: buttonshadow'>"
    > strHtml += "<tr><td><b>TabStrip</b> - " + Me.ID +

    "</td></tr>"
    > strHtml += "<tr><td>Please add Tabs through the Tabs
    > (Collection) property in the Properties pane,</td></tr>"
    > strHtml += "<tr><td>or by clicking ""Add New Tab"" in either
    > the description area of the</td></tr>"
    > strHtml += "<tr><td>Properties pane or the right-click
    > menu.</td></tr>"
    > strHtml += "<tr><td>Then switch to HTML view and edit each
    > Tab's view by inserting inner content.</td></tr></table>"
    > Return strHtml
    > End Function 'GetEmptyDesignTimeHtml
    >
    > Public Overrides Function GetDesignTimeHtml() As String
    >
    > Dim tabStrip As tabStrip = CType(Me.Component, tabStrip)
    > If Not (tabStrip Is Nothing) And tabStrip.Tabs.Count > 0 Then
    > Dim stringWriter As New stringWriter
    > Dim writer As New HtmlTextWriter(stringWriter)
    >
    > Dim _tabRows As Integer
    > Dim _fullRows As Integer
    > Dim _tabsInFullRow As Integer = tabStrip.TabsPerRow
    > Dim _tabsInPartRow As Integer
    > Dim _partRowTabWidth As Unit
    > Dim _fullRowTabWidth As Unit
    > Dim _fullRowRemainder As Integer
    > Dim _partRowRemainder As Integer
    > Dim _tabPageHeight As Unit
    > Dim _rowArray As Pair()()
    > Dim _tabIdx As Integer
    > Dim _selectedRow As Integer
    > Dim _autoPostBack As Boolean = tabStrip.AutoPostBack
    > Dim _tabHeight As Unit = tabStrip.TabHeight
    > Dim _width As Unit = tabStrip.Width
    > Dim _height As Unit = tabStrip.Height
    > Dim _tabCount As Integer = tabStrip.Tabs.Count
    >
    > 'get the widths of tabs in a full row
    > _fullRowTabWidth = Unit.Pixel(Math.Floor(_width.Value /
    > CDbl(_tabsInFullRow)))
    >
    > 'get the number of rows, total
    > _tabRows = CType(Math.Ceiling(CDbl(_tabCount) /
    > CDbl(_tabsInFullRow)), Integer)
    >
    > 'get the number of tabs in a partial row (a row with

    fewer
    > than TabsPerRow tabs)
    > If _tabRows * _tabsInFullRow = _tabCount Then
    > _fullRows = _tabRows
    > Else
    > _fullRows = _tabRows - 1
    > End If
    > _tabsInPartRow = _tabCount - (_fullRows * _tabsInFullRow)
    >
    > 'get the widths of tabs in a partial row
    > If _tabsInPartRow > 0 Then
    > _partRowTabWidth = Unit.Pixel(Math.Floor(_width.Value

    /
    > CDbl(_tabsInPartRow)))
    > Else
    > _partRowTabWidth = _fullRowTabWidth
    > End If
    >
    > 'but just in case they don't divide roundly, we need the
    > remainders
    > _fullRowRemainder = _width.Value - _fullRowTabWidth.Value

    *
    > _tabsInFullRow
    > _partRowRemainder = _width.Value - _partRowTabWidth.Value

    *
    > _tabsInPartRow
    >
    > 'figure out the height of the masterPage
    > _tabPageHeight = Unit.Pixel(_height.Value - (_tabRows *
    > _tabHeight.Value))
    >
    > 'let's make a jagged array that represents the tabs in
    > their rows
    > 'we'll put the tab widths in Pair.Second
    > ReDim _rowArray(_tabRows - 1)
    > For i As Integer = 0 To _tabRows - 1
    > If _fullRows < _tabRows And i = 0 Then
    > ReDim _rowArray(i)(_tabsInPartRow - 1)
    > For j As Integer = 0 To _tabsInPartRow - 1
    > If j = 0 Then
    > 'add in the remainder
    > _rowArray(i)(j) = New Pair(-1,
    > Unit.Pixel(_partRowTabWidth.Value + _partRowRemainder))
    > Else
    > _rowArray(i)(j) = New Pair(-1,
    > _partRowTabWidth)
    > End If
    > Next
    > Else
    > ReDim _rowArray(i)(_tabsInFullRow - 1)
    > For j As Integer = 0 To _tabsInFullRow - 1
    > If j = 0 Then
    > 'add in the remainder
    > _rowArray(i)(j) = New Pair(-1,
    > Unit.Pixel(_fullRowTabWidth.Value + _fullRowRemainder))
    > Else
    > _rowArray(i)(j) = New Pair(-1,
    > _fullRowTabWidth)
    > End If
    > Next
    > End If
    > Next
    >
    > 'now let's fill that array with tab indices (that goes

    into
    > Pair.First)
    > Dim _tabCollectionCounter As Integer = 0
    > Dim _tabCounter As Integer = 0
    > Dim _rowCounter As Integer = _tabRows - 1
    >
    > Do While _tabCollectionCounter < _tabCount
    > If tabStrip.Tabs(_tabCollectionCounter).Visible Then
    > _rowArray(_rowCounter)(_tabCounter).First =
    > _tabCollectionCounter
    > If _tabCollectionCounter =

    DesignTimeSelectedIndex
    > Then
    > _selectedRow = _rowCounter
    > End If
    > _tabCounter = _tabCounter + 1
    > If _tabCounter = _tabsInFullRow Then
    > _rowCounter = _rowCounter - 1
    > _tabCounter = 0
    > End If
    > End If
    > _tabCollectionCounter = _tabCollectionCounter + 1
    > Loop
    >
    > 'now let's do the rendering
    > writer.AddAttribute(HtmlTextWriterAttribute.Cellpadding,
    > "0", False)
    > writer.AddAttribute(HtmlTextWriterAttribute.Cellspacing,
    > "0", False)
    > writer.AddAttribute(HtmlTextWriterAttribute.Border, "0",
    > False)
    > writer.AddAttribute(HtmlTextWriterAttribute.Width,
    > _width.ToString, False)
    > writer.RenderBeginTag(HtmlTextWriterTag.Table)
    >
    > 'first do all the rows other than the selected row
    > For i As Integer = 0 To _rowArray.GetUpperBound(0)
    > If Not i = _selectedRow Then
    > writer.RenderBeginTag(HtmlTextWriterTag.Tr)
    >
    >

    writer.AddAttribute(HtmlTextWriterAttribute.Nowrap,
    > "true", False)
    >

    writer.AddAttribute(HtmlTextWriterAttribute.Valign,
    > "middle", False)
    > writer.RenderBeginTag(HtmlTextWriterTag.Td)
    >
    > For j As Integer = 0 To
    > _rowArray(i).getUpperBound(0)
    > _tabIdx = CInt(_rowArray(i)(j).First)
    > writer.AddStyleAttribute("border-bottom",
    > "none")
    > writer.AddStyleAttribute("height",
    > _tabHeight.Value.ToString)
    > writer.AddStyleAttribute("overflow",

    "hidden")
    > writer.AddStyleAttribute("text-align",
    > "center")
    > writer.AddStyleAttribute("font-family",
    > "system")
    > writer.AddStyleAttribute("font-size", "8pt")
    > writer.AddStyleAttribute("display", "inline")
    > writer.AddStyleAttribute("padding-top",

    "3px")
    > writer.AddStyleAttribute("border-left", "3px
    > outset")
    > writer.AddStyleAttribute("border-top", "3px
    > outset")
    > writer.AddStyleAttribute("border-right", "3px
    > outset")
    > writer.AddStyleAttribute("cursor", "hand")
    >
    > writer.AddStyleAttribute(HtmlTextWriterStyle.Width,
    > CType(_rowArray(i)(j).Second, Unit).ToString)
    >
    > writer.AddStyleAttribute(HtmlTextWriterStyle.Color,
    > tabStrip.Tabs(_tabIdx).ForeColor.Name)
    >
    > writer.AddStyleAttribute(HtmlTextWriterStyle.BackgroundColor,
    > tabStrip.Tabs(_tabIdx).BackColor.Name)
    >
    > writer.RenderBeginTag(HtmlTextWriterTag.Div)
    > writer.Write(tabStrip.Tabs(_tabIdx).Text)
    > writer.RenderEndTag() 'Div
    > Next
    >
    > writer.RenderEndTag() 'Td
    > writer.RenderEndTag() 'Tr
    > End If
    > Next
    >
    > 'then do the selected row
    > writer.RenderBeginTag(HtmlTextWriterTag.Tr)
    >
    > writer.AddAttribute(HtmlTextWriterAttribute.Nowrap,

    "true",
    > False)
    > writer.AddAttribute(HtmlTextWriterAttribute.Valign,
    > "middle", False)
    > writer.RenderBeginTag(HtmlTextWriterTag.Td)
    >
    > For j As Integer = 0 To
    > _rowArray(_selectedRow).GetUpperBound(0)
    > _tabIdx = CInt(_rowArray(_selectedRow)(j).First)
    > If _rowArray(_selectedRow)(j).First =
    > DesignTimeSelectedIndex Then
    > writer.AddStyleAttribute("border-bottom", "none")
    > Else
    > writer.AddStyleAttribute("border-bottom", "3px
    > inset")
    > End If
    > writer.AddStyleAttribute("height",
    > _tabHeight.Value.ToString)
    > writer.AddStyleAttribute("overflow", "hidden")
    > writer.AddStyleAttribute("text-align", "center")
    > writer.AddStyleAttribute("font-family", "system")
    > writer.AddStyleAttribute("font-size", "8pt")
    > writer.AddStyleAttribute("display", "inline")
    > writer.AddStyleAttribute("padding-top", "3px")
    > writer.AddStyleAttribute("border-left", "3px outset")
    > writer.AddStyleAttribute("border-top", "3px outset")
    > writer.AddStyleAttribute("border-right", "3px

    outset")
    > writer.AddStyleAttribute("cursor", "hand")
    > writer.AddStyleAttribute(HtmlTextWriterStyle.Width,
    > CType(_rowArray(_selectedRow)(j).Second, Unit).ToString)
    > writer.AddStyleAttribute(HtmlTextWriterStyle.Color,
    > tabStrip.Tabs(_tabIdx).ForeColor.Name)
    >
    > writer.AddStyleAttribute(HtmlTextWriterStyle.BackgroundColor,
    > tabStrip.Tabs(_tabIdx).BackColor.Name)
    >
    > writer.RenderBeginTag(HtmlTextWriterTag.Div)
    > writer.Write(tabStrip.Tabs(_tabIdx).Text)
    > writer.RenderEndTag() 'Div
    > Next
    >
    > writer.RenderEndTag() 'Td
    > writer.RenderEndTag() 'Tr
    >
    > 'so much for the tabs. Now the tab pages/panels
    > writer.RenderBeginTag(HtmlTextWriterTag.Tr)
    > writer.RenderBeginTag(HtmlTextWriterTag.Td)
    >
    >
    > writer.AddStyleAttribute(HtmlTextWriterStyle.BackgroundColor,
    > tabStrip.Tabs(tabStrip.SelectedIndex).BackColor.Name)
    > writer.AddStyleAttribute("overflow", "auto")
    > writer.AddStyleAttribute("border-left", "3px outset")
    > writer.AddStyleAttribute("border-bottom", "3px outset")
    > writer.AddStyleAttribute("border-right", "3px outset")
    > writer.AddStyleAttribute("display", "inline")
    > writer.AddStyleAttribute(HtmlTextWriterStyle.Height,
    > _tabPageHeight.ToString)
    > writer.AddStyleAttribute(HtmlTextWriterStyle.Width,
    > _width.ToString)
    > writer.RenderBeginTag(HtmlTextWriterTag.Div)
    >
    > For Each myTab As Tab In tabStrip.Tabs
    > ' Only render the TabView under the following
    > conditions:
    > ' (1) AutoPostBack is set to false.
    > ' (2) AutoPostBack is set to true, and the TabView is
    > for the Selected Tab
    > If DesignTimeSelectedIndex =
    > tabStrip.Tabs.IndexOf(myTab) Then
    >

    writer.AddStyleAttribute(HtmlTextWriterStyle.Width,
    > myTab.InnerWidth.ToString)
    >
    > writer.AddStyleAttribute(HtmlTextWriterStyle.Height,
    > myTab.InnerHeight.ToString)
    >
    > writer.AddStyleAttribute(HtmlTextWriterStyle.BackgroundColor,
    > myTab.BackColor.Name)
    >

    writer.AddStyleAttribute(HtmlTextWriterStyle.Color,
    > myTab.ForeColor.Name)
    > writer.AddStyleAttribute("text-align", "center")
    > writer.RenderBeginTag(HtmlTextWriterTag.Div)
    >
    > If myTab.HasControls() = False Then
    > myTab.Controls.Add(New
    > LiteralControl("&nbsp;"))
    > End If
    >
    > For Each myControl As Control In myTab.Controls
    > myControl.RenderControl(writer)
    > Next
    >
    > writer.RenderEndTag() 'Div
    > End If
    > Next
    >
    > writer.RenderEndTag() 'Div
    > writer.RenderEndTag() 'Td
    > writer.RenderEndTag() 'Tr
    > writer.RenderEndTag() 'Table
    >
    > Return stringWriter.ToString()
    > Else
    > Return Me.GetEmptyDesignTimeHtml()
    > End If
    >
    > End Function 'GetDesignTimeHtml
    >
    > Private Sub OnSelectionChanged(ByVal sender As Object, ByVal e As
    > EventArgs)
    > Dim ss As ISelectionService = CType(sender,

    ISelectionService)
    > If Not (ss Is Nothing) Then
    > Dim bTabControlSelected As Boolean =
    > ss.GetComponentSelected(Me.Component)
    > If bTabControlSelected Then
    > ModifyMenu()
    > End If
    > End If
    > End Sub 'OnSelectionChanged
    >
    > Private Sub ModifyMenu()
    > Dim tabStrip As tabStrip = CType(Me.Component, tabStrip)
    > verbShowNextTab.Visible = False
    > verbRemoveTab.Visible = False
    > verbShowNextTab.Visible = tabStrip.Tabs.Count > 1
    > verbRemoveTab.Visible = tabStrip.Tabs.Count > 0
    > End Sub 'ModifyMenu
    >
    > Private Sub AddTab(ByVal sender As Object, ByVal e As EventArgs)
    > Dim tabStrip As tabStrip = CType(Me.Component, tabStrip)
    > Dim myTab As New Tab
    > tabStrip.Tabs.Add(myTab)
    > tabStrip.Controls.Add(myTab)
    > myTab.Text = "Tab " & tabStrip.Tabs.Count.ToString
    > myTab.ID = myTab.ClientID
    > DesignTimeSelectedIndex = tabStrip.Tabs.Count - 1
    > OnComponentChanged(Me, New

    ComponentChangedEventArgs(tabStrip,
    > Nothing, Nothing, Nothing))
    > End Sub 'AddTab
    >
    > Private Sub ShowNextTab(ByVal sender As Object, ByVal e As
    > EventArgs)
    > Dim tabStrip As tabStrip = CType(Me.Component, tabStrip)
    > Dim TabCount As Integer = tabStrip.Tabs.Count
    > If TabCount > 0 Then
    > DesignTimeSelectedIndex = (DesignTimeSelectedIndex + 1)

    Mod
    > TabCount
    > UpdateDesignTimeHtml()
    > End If
    > End Sub 'ShowNextTab
    >
    > Private Sub RemoveTab(ByVal sender As Object, ByVal e As

    EventArgs)
    > Dim tabStrip As tabStrip = CType(Me.Component, tabStrip)
    > If tabStrip.Tabs.Count > 0 Then
    > tabStrip.Tabs.RemoveAt(DesignTimeSelectedIndex)
    > ' Ensure the selected index is still valid.
    > ' It is possible that the selected Tab was the last one,
    > ' and that one was removed.
    > If tabStrip.SelectedIndex >= tabStrip.Tabs.Count Then
    > tabStrip.SelectedIndex = tabStrip.Tabs.Count - 1
    > If tabStrip.SelectedIndex < 0 Then
    > tabStrip.SelectedIndex = 0
    > End If
    > End If
    > ' Commit the Change
    > OnComponentChanged(Me, New
    > ComponentChangedEventArgs(tabStrip, Nothing, Nothing, Nothing))
    > ' Show the closest, right-most sibling Tab in the

    Designer
    > DesignTimeSelectedIndex -= 1
    > If DesignTimeSelectedIndex + 1 >= tabStrip.Tabs.Count

    Then
    > DesignTimeSelectedIndex -= 1
    > End If
    > ShowNextTab(Me, EventArgs.Empty)
    > End If
    > End Sub 'RemoveTab
    >
    > End Class 'TabControlDesigner
    , May 2, 2005
    #2
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Feng
    Replies:
    1
    Views:
    398
    Craig Deelsnyder
    Jul 28, 2003
  2. Dylan
    Replies:
    5
    Views:
    409
    Daniel T.
    Mar 22, 2005
  3. flamesrock
    Replies:
    8
    Views:
    434
    Hendrik van Rooyen
    Nov 24, 2006
  4. Øyvind Isaksen
    Replies:
    1
    Views:
    941
    Øyvind Isaksen
    May 18, 2007
  5. Pierre Yves
    Replies:
    2
    Views:
    469
    Pierre Yves
    Jan 10, 2008
Loading...

Share This Page