Why don't child control events trigger OnBubbleEvent?

Discussion in 'ASP .Net Web Controls' started by lisa@starways.net, May 10, 2005.

  1. Guest

    I have a control which contains a collection of another control. The
    members of the collection can contain child controls themselves, but
    these aren't coded. They are merely added between the start and end
    tags of the child controls in the HTML view.

    If I put a button (for instance) inside one of the child controls, the
    button's click event causes a postback, but then seems to disappear
    entirely. I tried looking at OnBubbleEvent in the child control and in
    the parent control. Those events are never called. Nor does the
    button's click event in the page containing the control ever get
    called.

    Is there a way to capture events of such child controls? I get the
    feeling that these child controls aren't being added to the control
    hierarchy of the parent control, but they are visible when I do
    ParentControl.ChildrenControls(idx).Controls(idx2), so maybe they are
    in the control hierarchy.

    I'm completely stumped here, and I'd appreciate any suggestions.

    TIA,
    Lisa
     
    , May 10, 2005
    #1
    1. Advertising

  2. Brock Allen Guest

    Post your code, as that will help in determining what's going on.

    -Brock
    DevelopMentor
    http://staff.develop.com/ballen



    > I have a control which contains a collection of another control. The
    > members of the collection can contain child controls themselves, but
    > these aren't coded. They are merely added between the start and end
    > tags of the child controls in the HTML view.
    >
    > If I put a button (for instance) inside one of the child controls, the
    > button's click event causes a postback, but then seems to disappear
    > entirely. I tried looking at OnBubbleEvent in the child control and
    > in the parent control. Those events are never called. Nor does the
    > button's click event in the page containing the control ever get
    > called.
    >
    > Is there a way to capture events of such child controls? I get the
    > feeling that these child controls aren't being added to the control
    > hierarchy of the parent control, but they are visible when I do
    > ParentControl.ChildrenControls(idx).Controls(idx2), so maybe they are
    > in the control hierarchy.
    >
    > I'm completely stumped here, and I'd appreciate any suggestions.
    >
    > TIA,
    > Lisa
     
    Brock Allen, May 10, 2005
    #2
    1. Advertising

  3. Guest

    It's a bit long, but here it is. I appreciate the help.

    Thanks,
    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
    'todo: I need to find a way to get the contained controls to postback

    <ToolboxData("<{0}:TabControl runat=server></{0}:TabControl>"),
    Designer(GetType(TabControlDesigner)), PersistChildren(False),
    ParseChildren(True, "Tabs"), DefaultProperty("Tabs"),
    DefaultEvent("SelectedIndexChanged")> _
    Public Class TabControl
    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 _tabFontFamily As String = "System"
    Private _tabFontSize As FontUnit = FontUnit.Point(8)
    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 _rowArray As Pair()()
    Private _selectedRow As Integer
    Private _tabIdx As Integer

    Private _propertyChangedList As DropDownList

    #Region "Properties"

    <Category("Behavior"), Description("The collection of tabs."),
    DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
    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),
    PersistenceMode(PersistenceMode.Attribute)> _
    Public Property TabsPerRow() As Integer
    Get
    Return _tabsPerRow
    End Get
    Set(ByVal Value As Integer)
    If Value < 1 Then
    Value = 1
    End If
    _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 'SelectedIndex

    <Category("Behavior"), Description("Whether or not the control
    posts back when you change tabs.")> _
    Public Property AutoPostBack() As Boolean
    Get
    Return _autoPostBack
    End Get
    Set(ByVal Value As Boolean)
    _autoPostBack = Value
    End Set
    End Property 'AutoPostBack

    <Category("Appearance"), Description("The font-family of the tab
    text.")> _
    Public Property TabFontFamily() As String
    Get
    Return _tabFontFamily
    End Get
    Set(ByVal Value As String)
    If Value Is Nothing Then
    Value = "System"
    End If
    _tabFontFamily = Value
    End Set
    End Property 'TabFontFamily

    <Category("Appearance"), Description("The font-size of the tab
    text.")> _
    Public Property TabFontSize() As FontUnit
    Get
    Return _tabFontSize
    End Get
    Set(ByVal Value As FontUnit)
    If Value.IsEmpty Then
    Value = FontUnit.Point(8)
    End If
    _tabFontSize = Value
    End Set
    End Property 'TabFontSize

    #End Region

    #Region "WebControl Properties to Hide"

    <Browsable(False)> _
    Public Shadows ReadOnly Property Visible() As Boolean
    Get
    Return True
    End Get
    End Property 'Visible

    <Browsable(False)> _
    Public Shadows ReadOnly Property ForeColor() As
    System.Drawing.Color
    Get
    Return System.Drawing.Color.Empty
    End Get
    End Property 'ForeColor

    <Browsable(False)> _
    Public Shadows ReadOnly Property BackColor() As
    System.Drawing.Color
    Get
    Return System.Drawing.Color.Empty
    End Get
    End Property 'BackColor

    <Browsable(False)> _
    Public Shadows ReadOnly Property BorderColor() As
    System.Drawing.Color
    Get
    Return System.Drawing.Color.Empty
    End Get
    End Property 'BorderColor

    <Browsable(False)> _
    Public Shadows ReadOnly Property BorderStyle() As BorderStyle
    Get
    Return Nothing
    End Get
    End Property 'BorderStyle

    <Browsable(False)> _
    Public Shadows ReadOnly Property BorderWidth() As Unit
    Get
    Return Nothing
    End Get
    End Property 'BorderWidth

    <Browsable(False)> _
    Public Shadows ReadOnly Property CssClass() As String
    Get
    Return String.Empty
    End Get
    End Property 'CssClass

    <Browsable(False)> _
    Public Shadows ReadOnly Property Font() As System.Drawing.Font
    Get
    Return Nothing
    End Get
    End Property 'Font

    <Browsable(False)> _
    Public Shadows ReadOnly Property EnableViewState() As Boolean
    Get
    Return True
    End Get
    End Property 'EnableViewState

    <Browsable(False)> _
    Public Shadows ReadOnly Property AccessKey() As String
    Get
    Return String.Empty
    End Get
    End Property 'AccessKey

    #End Region

    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("TabControl_vbs")
    Then
    Dim reader As New
    System.IO.StreamReader(Me.GetType().Assembly.GetManifestResourceStream(Me.GetType(),
    "TabControl.vbs"))
    Dim script As String = "<script language='vbscript'
    type='text/vbscript' >" _
    + ControlChars.CrLf _
    + "<!--" _
    + ControlChars.CrLf _
    + reader.ReadToEnd() _
    + ControlChars.CrLf _
    + "//-->" _
    + ControlChars.CrLf _
    + "</script>"
    Page.RegisterClientScriptBlock("TabControl_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 > Tabs.Count -
    1 Then
    _selectedIndex = 0
    End If
    End If

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

    End Function 'GetSelectedIndexForRender

    Private Sub GetTabFormatValuesForRender()

    Dim _tabCount As Integer = Tabs.Count

    '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(_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(-5,
    Unit.Pixel(_partRowTabWidth.Value + _partRowRemainder))
    Else
    _rowArray(i)(j) = New Pair(-4,
    _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(-3,
    Unit.Pixel(_fullRowTabWidth.Value + _fullRowRemainder))
    Else
    _rowArray(i)(j) = New Pair(-2,
    _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

    _tabCount = Tabs.Count

    Do While _tabCollectionCounter < _tabCount
    _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

    _tabCollectionCounter = _tabCollectionCounter + 1
    Loop

    End Sub 'GetTabFormatValuesForRender

    Private Sub ApplyChildPostBack()

    'Populate controls with PostData, saving a list of those that
    were modified:
    Dim IsChanged As Boolean
    Dim requestForm As New
    System.Collections.Specialized.NameValueCollection(Page.Request.Form)
    Dim propertyChangedList As String = requestForm(Me.ClientID &
    ":propertyChangedList")
    If propertyChangedList Is Nothing Then
    Exit Sub
    End If

    Dim changedControls() As String =
    propertyChangedList.Split(",")
    Dim modifiedControls As New ArrayList
    For Each myTab As Tab In Tabs
    For Each myControl As Control In myTab.Controls
    If TypeOf myControl Is IPostBackDataHandler Then
    'If a property has changed on a control, update it
    IsChanged = False
    For i As Integer = 0 To changedControls.Length - 1
    If changedControls(i) = myControl.ID Then
    IsChanged = True
    Exit For
    End If
    Next
    If IsChanged Then
    If CType(myControl,
    IPostBackDataHandler).LoadPostData(myControl.ID, requestForm) Then
    modifiedControls.Add(myControl)
    End If
    End If
    End If
    Next myControl
    Next myTab

    'Raise PostDataChanged event on all modified controls:
    Dim modifiedControl As IPostBackDataHandler
    For Each modifiedControl In modifiedControls
    modifiedControl.RaisePostDataChangedEvent()
    Next modifiedControl

    End Sub 'ApplyChildPostBack

    Protected Overrides Sub CreateChildControls()
    MyBase.CreateChildControls()
    _propertyChangedList = New DropDownList
    _propertyChangedList.ID = "PropertyChangedList"
    _propertyChangedList.Attributes.Add("style", "display:none")
    Controls.Add(_propertyChangedList)
    End Sub 'CreateChildControls

    Protected Overrides Sub Render(ByVal writer As HtmlTextWriter)

    '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()

    'a kludgy thing to get around the fact that the contents of
    tabs
    'aren't seen by the page, and therefore aren't updated
    ApplyChildPostBack()

    '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("text-align", "center")
    writer.AddStyleAttribute("text-align", "center")
    writer.AddStyleAttribute("font-family",
    TabFontFamily)
    writer.AddStyleAttribute("font-size",
    TabFontSize.ToString)
    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")
    If Tabs(_tabIdx).Enabled Then
    writer.AddStyleAttribute("cursor", "hand")
    If Not Tabs(_tabIdx).ToolTip.Trim = "" Then
    writer.AddAttribute("title",
    Tabs(_tabIdx).ToolTip, True)
    End If
    '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,
    "TabControl_SelectTab(me)", False)
    End If
    Else
    writer.AddAttribute("disabled", "true")
    End If
    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)
    writer.AddAttribute(HtmlTextWriterAttribute.Name,
    Me.ClientID & "_tab_" & _tabIdx.ToString, False)
    writer.AddAttribute(HtmlTextWriterAttribute.Id,
    Me.ClientID & "_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", TabFontFamily)
    writer.AddStyleAttribute("font-size", TabFontSize.ToString)
    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")
    If Tabs(_tabIdx).Enabled Then
    writer.AddStyleAttribute("cursor", "hand")
    If Not Tabs(_tabIdx).ToolTip.Trim = "" Then
    writer.AddAttribute("title", Tabs(_tabIdx).ToolTip,
    True)
    End If
    '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,
    "TabControl_SelectTab(me)", False)
    End If
    Else
    writer.AddAttribute("disabled", "true")
    End If
    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)
    writer.AddAttribute(HtmlTextWriterAttribute.Name,
    Me.ClientID & "_tab_" & _tabIdx.ToString, False)
    writer.AddAttribute(HtmlTextWriterAttribute.Id, Me.ClientID
    & "_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
    'this is so that we can update property changes on
    postback
    If TypeOf myControl Is IPostBackDataHandler Then
    writer.AddAttribute("onpropertychange",
    "TabControl_FlagChange '" & myControl.ClientID & "', '" &
    _propertyChangedList.ClientID & "'")
    End If
    myControl.RenderControl(writer)
    Next

    writer.RenderEndTag() 'Div
    End If
    Next

    writer.RenderEndTag() 'Div
    'this is so that we can update property changes on postback
    _propertyChangedList.RenderControl(writer)
    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

    Protected Overrides Function OnBubbleEvent(ByVal source As Object,
    ByVal args As System.EventArgs) As Boolean
    Return False
    End Function 'OnBubbleEvent

    End Class 'TabControl

    <ToolboxItem(False), ParseChildren(False), PersistChildren(True)> _
    Public Class Tab
    Inherits WebControl

    Private _text As String
    Private _innerHeight As Unit
    Private _innerWidth As Unit
    Private _id As String

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

    #Region "Properties"

    <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(False)> _
    Public Overrides Property ID() As String
    Get
    Return _id
    End Get
    Set(ByVal Value As String)
    _id = Value
    End Set
    End Property

    #End Region

    #Region "WebControl Properties to Hide"

    <Browsable(False)> _
    Public Shadows ReadOnly Property Visible() As Boolean
    Get
    Return True
    End Get
    End Property 'Visible

    <Browsable(False)> _
    Public Shadows ReadOnly Property BorderColor() As
    System.Drawing.Color
    Get
    Return System.Drawing.Color.Empty
    End Get
    End Property 'BorderColor

    <Browsable(False)> _
    Public Shadows ReadOnly Property BorderStyle() As BorderStyle
    Get
    Return Nothing
    End Get
    End Property 'BorderStyle

    <Browsable(False)> _
    Public Shadows ReadOnly Property BorderWidth() As Unit
    Get
    Return Nothing
    End Get
    End Property 'BorderWidth

    <Browsable(False)> _
    Public Shadows ReadOnly Property CssClass() As String
    Get
    Return String.Empty
    End Get
    End Property 'CssClass

    <Browsable(False)> _
    Public Shadows ReadOnly Property Font() As System.Drawing.Font
    Get
    Return Nothing
    End Get
    End Property 'Font

    <Browsable(False)> _
    Public Shadows ReadOnly Property Height() As Unit
    Get
    Return Unit.Empty
    End Get
    End Property 'Height

    <Browsable(False)> _
    Public Shadows ReadOnly Property Width() As Unit
    Get
    Return Unit.Empty
    End Get
    End Property 'Width

    <Browsable(False)> _
    Public Shadows ReadOnly Property EnableViewState() As Boolean
    Get
    Return True
    End Get
    End Property 'EnableViewState

    <Browsable(False)> _
    Public Shadows ReadOnly Property AccessKey() As String
    Get
    Return String.Empty
    End Get
    End Property 'AccessKey

    #End Region

    Protected Overrides Function OnBubbleEvent(ByVal source As Object,
    ByVal args As System.EventArgs) As Boolean
    Return False
    End Function 'OnBubbleEvent

    End Class 'Tab

    Public Class TabCollection
    Inherits CollectionBase

    Default Public ReadOnly Property Item(ByVal index As Integer) As
    Tab
    Get
    If index < 0 Or index >= MyBase.List.Count Then
    Stop
    End If
    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 TabControlDesigner
    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 tabControl As tabControl = CType(component, tabControl)
    DesignTimeSelectedIndex = tabControl.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;
    display: inline'>"
    strHtml += "<tr><td><b>TabControl</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 tabControl As tabControl = CType(Me.Component, tabControl)
    If Not (tabControl Is Nothing) And tabControl.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 = tabControl.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 = tabControl.AutoPostBack
    Dim _tabHeight As Unit = tabControl.TabHeight
    Dim _tabFontFamily As String = tabControl.TabFontFamily
    Dim _tabFontSize As FontUnit = tabControl.TabFontSize
    Dim _width As Unit = tabControl.Width
    Dim _height As Unit = tabControl.Height
    Dim _tabCount As Integer = tabControl.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
    _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

    _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",
    _tabFontFamily)
    writer.AddStyleAttribute("font-size",
    _tabFontSize.ToString)
    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,
    tabControl.Tabs(_tabIdx).ForeColor.Name)

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

    writer.RenderBeginTag(HtmlTextWriterTag.Div)
    writer.Write(tabControl.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", _tabFontFamily)
    writer.AddStyleAttribute("font-size",
    _tabFontSize.ToString)
    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,
    tabControl.Tabs(_tabIdx).ForeColor.Name)

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

    writer.RenderBeginTag(HtmlTextWriterTag.Div)
    writer.Write(tabControl.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,
    tabControl.Tabs(tabControl.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 tabControl.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 =
    tabControl.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 tabControl As tabControl = CType(Me.Component, tabControl)
    verbShowNextTab.Visible = False
    verbRemoveTab.Visible = False
    verbShowNextTab.Visible = tabControl.Tabs.Count > 1
    verbRemoveTab.Visible = tabControl.Tabs.Count > 0
    End Sub 'ModifyMenu

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

    Private Sub ShowNextTab(ByVal sender As Object, ByVal e As
    EventArgs)
    Dim tabControl As tabControl = CType(Me.Component, tabControl)
    Dim TabCount As Integer = tabControl.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 tabControl As tabControl = CType(Me.Component, tabControl)
    If tabControl.Tabs.Count > 0 Then
    tabControl.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 tabControl.SelectedIndex >= tabControl.Tabs.Count Then
    tabControl.SelectedIndex = tabControl.Tabs.Count - 1
    If tabControl.SelectedIndex < 0 Then
    tabControl.SelectedIndex = 0
    End If
    End If
    ' Commit the Change
    OnComponentChanged(Me, New
    ComponentChangedEventArgs(tabControl, Nothing, Nothing, Nothing))
    ' Show the closest, right-most sibling Tab in the Designer
    DesignTimeSelectedIndex -= 1
    If DesignTimeSelectedIndex + 1 >= tabControl.Tabs.Count
    Then
    DesignTimeSelectedIndex -= 1
    End If
    ShowNextTab(Me, EventArgs.Empty)
    End If
    End Sub 'RemoveTab

    End Class 'TabControlDesigner


    Brock Allen wrote:
    > Post your code, as that will help in determining what's going on.
    >
    > -Brock
    > DevelopMentor
    > http://staff.develop.com/ballen
    >
    >
    >
    > > I have a control which contains a collection of another control.

    The
    > > members of the collection can contain child controls themselves,

    but
    > > these aren't coded. They are merely added between the start and

    end
    > > tags of the child controls in the HTML view.
    > >
    > > If I put a button (for instance) inside one of the child controls,

    the
    > > button's click event causes a postback, but then seems to disappear
    > > entirely. I tried looking at OnBubbleEvent in the child control

    and
    > > in the parent control. Those events are never called. Nor does

    the
    > > button's click event in the page containing the control ever get
    > > called.
    > >
    > > Is there a way to capture events of such child controls? I get the
    > > feeling that these child controls aren't being added to the control
    > > hierarchy of the parent control, but they are visible when I do
    > > ParentControl.ChildrenControls(idx).Controls(idx2), so maybe they

    are
    > > in the control hierarchy.
    > >
    > > I'm completely stumped here, and I'd appreciate any suggestions.
    > >
    > > TIA,
    > > Lisa
     
    , May 10, 2005
    #3
  4. Brock Allen Guest

    > It's a bit long, but here it is. I appreciate the help.

    Ugg, I should have said "post the smallest amount of code that reproduces
    the problem".

    Ok, so I skimmed the code and, IIRC, your problem is that declared controls
    aren't getting server side events called? I think past of the problem is
    that the controls aren't part of the control hierarchy... meaning, I don't
    see where the controls that are in the TabdCollection are ever added into
    the control tree. If they're not in the control tree then they miss out on
    a lot of the server side processing. Again, that was a huge code dump, so
    my quick glance at it might be off.

    -Brock
    DevelopMentor
    http://staff.develop.com/ballen
     
    Brock Allen, May 10, 2005
    #4
  5. Guest

    Brock Allen wrote:
    > > It's a bit long, but here it is. I appreciate the help.

    >
    > Ugg, I should have said "post the smallest amount of code that

    reproduces
    > the problem".


    I'm sorry. I honestly wasn't sure what part that would be. Although I
    suppose I could have left out the designer. <sheepish grin>

    > Ok, so I skimmed the code and, IIRC, your problem is that declared

    controls
    > aren't getting server side events called? I think past of the problem

    is
    > that the controls aren't part of the control hierarchy... meaning, I

    don't
    > see where the controls that are in the TabdCollection are ever added

    into
    > the control tree. If they're not in the control tree then they miss

    out on
    > a lot of the server side processing. Again, that was a huge code

    dump, so
    > my quick glance at it might be off.


    I apologize for the size, Brock. Here is what it looks like in the
    HTML at design time:

    <fw:TabControl id="TabControl1" runat="server">
    <fw:Tab ID="TabControl1__ctl0" Text="Tab 1">&nbsp;</fw:Tab>
    <fw:Tab ID="TabControl1__ctl1" Text="Tab 2">
    <asp:Button id="Button1" runat="server" Text="Button" />
    </fw:Tab>
    </fw:TabControl>

    When I dragged it onto the form and added two tabs, it looked just like
    this, except that there was a non-breaking space where the button is.

    When I'm in run time, I see this in the Command Window:

    ?me.Tabs(1).Controls(1).ID
    "Button1"

    "Me", in this case, is the TabControl. Maybe I don't understand the
    control hierarchy, but doesn't the fact that I can reference the button
    at run time this way mean that the button is part of the control
    hierarchy?

    In terms of how the Tabs themselves are added, the TabCollection has
    this:

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

    And the TabControl has this in global declarations:

    Private _tabs As New TabCollection

    And it has this property:

    Public ReadOnly Property Tabs() As TabCollection
    Get
    Return _tabs
    End Get
    End Property

    Assuming that that's all the relevant code (which I'm unsure of), do
    you see what could be causing my problem? Since the Button is already
    visible at run time as a child of the second tab, I don't know what I
    could add the Button to without it creating a second Button.

    The Microsoft Multipage control works the same way. I can add a Button
    (let's say) between the start and end tags of a PageView control
    (analogous to my Tab control), and somehow, the Button's events are
    called properly. The biggest difference I can see is that their
    PageViewCollection is derived from ControlCollection, while my
    TabCollection is derived from CollectionBase. But I can't see how that
    could be causing the problems.

    I really appreciate the help, Brock.

    Lisa
     
    , May 10, 2005
    #5
  6. Guest

    Brock? (was Re: Why don't child control events trigger OnBubbleEvent?)

    I'm sorry to bother you, but I was wondering if you'd had a chance to
    take a look at this.

    Thanks,
    Lisa


    wrote:
    > Brock Allen wrote:
    > > > It's a bit long, but here it is. I appreciate the help.

    > >
    > > Ugg, I should have said "post the smallest amount of code that
    > > reproduces the problem".

    >
    > I'm sorry. I honestly wasn't sure what part that would be. Although

    I
    > suppose I could have left out the designer. <sheepish grin>
    >
    > > Ok, so I skimmed the code and, IIRC, your problem is that declared
    > > controls aren't getting server side events called? I think past of
    > > the problem is that the controls aren't part of the control
    > > hierarchy... meaning, I don't see where the controls that are in

    the
    > > TabdCollection are ever added into the control tree. If they're not


    > > in the control tree then they miss out on a lot of the server side
    > > processing. Again, that was a huge code dump, so my quick glance at


    > > it might be off.

    >
    > I apologize for the size, Brock. Here is what it looks like in the
    > HTML at design time:
    >
    > <fw:TabControl id="TabControl1" runat="server">
    > <fw:Tab ID="TabControl1__ctl0" Text="Tab 1">&nbsp;</fw:Tab>
    > <fw:Tab ID="TabControl1__ctl1" Text="Tab 2">
    > <asp:Button id="Button1" runat="server" Text="Button" />
    > </fw:Tab>
    > </fw:TabControl>
    >
    > When I dragged it onto the form and added two tabs, it looked just

    like
    > this, except that there was a non-breaking space where the button is.
    >
    > When I'm in run time, I see this in the Command Window:
    >
    > ?me.Tabs(1).Controls(1).ID
    > "Button1"
    >
    > "Me", in this case, is the TabControl. Maybe I don't understand the
    > control hierarchy, but doesn't the fact that I can reference the

    button
    > at run time this way mean that the button is part of the control
    > hierarchy?
    >
    > In terms of how the Tabs themselves are added, the TabCollection has
    > this:
    >
    > Public Sub Add(ByVal myTab As Tab)
    > MyBase.List.Add(myTab)
    > End Sub 'Add
    >
    > And the TabControl has this in global declarations:
    >
    > Private _tabs As New TabCollection
    >
    > And it has this property:
    >
    > Public ReadOnly Property Tabs() As TabCollection
    > Get
    > Return _tabs
    > End Get
    > End Property
    >
    > Assuming that that's all the relevant code (which I'm unsure of), do
    > you see what could be causing my problem? Since the Button is

    already
    > visible at run time as a child of the second tab, I don't know what I
    > could add the Button to without it creating a second Button.
    >
    > The Microsoft Multipage control works the same way. I can add a

    Button
    > (let's say) between the start and end tags of a PageView control
    > (analogous to my Tab control), and somehow, the Button's events are
    > called properly. The biggest difference I can see is that their
    > PageViewCollection is derived from ControlCollection, while my
    > TabCollection is derived from CollectionBase. But I can't see how

    that
    > could be causing the problems.
    >
    > I really appreciate the help, Brock.
    >
    > Lisa
     
    , May 12, 2005
    #6
  7. Brock Allen Guest

    Sorry Lisa, I can't quite tell exactly what the problem is from this. What
    I'd suggest is to build a small sample outside of your current project that
    works the way you want it and then try to compare the differences. Here are
    some samples that might get you started:

    http://msdn.microsoft.com/library/d...stomizingcontrolswithtemplates.asp?frame=true

    http://winfx.msdn.microsoft.com/lib...html/986f63b8-6b50-42b9-a62d-a2f13cafa88b.asp

    And more of the same here:

    http://samples.gotdotnet.com/quicks.../quickstart/aspplus/doc/webctrlauthoring.aspx

    -Brock
    DevelopMentor
    http://staff.develop.com/ballen



    > Brock Allen wrote:
    >
    >>> It's a bit long, but here it is. I appreciate the help.
    >>>

    >> Ugg, I should have said "post the smallest amount of code that
    >>

    > reproduces
    >
    >> the problem".
    >>

    > I'm sorry. I honestly wasn't sure what part that would be. Although
    > I suppose I could have left out the designer. <sheepish grin>
    >
    >> Ok, so I skimmed the code and, IIRC, your problem is that declared
    >>

    > controls
    >
    >> aren't getting server side events called? I think past of the problem
    >>

    > is
    >
    >> that the controls aren't part of the control hierarchy... meaning, I
    >>

    > don't
    >
    >> see where the controls that are in the TabdCollection are ever added
    >>

    > into
    >
    >> the control tree. If they're not in the control tree then they miss
    >>

    > out on
    >
    >> a lot of the server side processing. Again, that was a huge code
    >>

    > dump, so
    >
    >> my quick glance at it might be off.
    >>

    > I apologize for the size, Brock. Here is what it looks like in the
    > HTML at design time:
    >
    > <fw:TabControl id="TabControl1" runat="server">
    > <fw:Tab ID="TabControl1__ctl0" Text="Tab 1">&nbsp;</fw:Tab>
    > <fw:Tab ID="TabControl1__ctl1" Text="Tab 2">
    > <asp:Button id="Button1" runat="server" Text="Button" />
    > </fw:Tab>
    > </fw:TabControl>
    > When I dragged it onto the form and added two tabs, it looked just
    > like this, except that there was a non-breaking space where the button
    > is.
    >
    > When I'm in run time, I see this in the Command Window:
    >
    > ?me.Tabs(1).Controls(1).ID
    > "Button1"
    > "Me", in this case, is the TabControl. Maybe I don't understand the
    > control hierarchy, but doesn't the fact that I can reference the
    > button at run time this way mean that the button is part of the
    > control hierarchy?
    >
    > In terms of how the Tabs themselves are added, the TabCollection has
    > this:
    >
    > Public Sub Add(ByVal myTab As Tab)
    > MyBase.List.Add(myTab)
    > End Sub 'Add
    > And the TabControl has this in global declarations:
    >
    > Private _tabs As New TabCollection
    >
    > And it has this property:
    >
    > Public ReadOnly Property Tabs() As TabCollection
    > Get
    > Return _tabs
    > End Get
    > End Property
    > Assuming that that's all the relevant code (which I'm unsure of), do
    > you see what could be causing my problem? Since the Button is already
    > visible at run time as a child of the second tab, I don't know what I
    > could add the Button to without it creating a second Button.
    >
    > The Microsoft Multipage control works the same way. I can add a
    > Button (let's say) between the start and end tags of a PageView
    > control (analogous to my Tab control), and somehow, the Button's
    > events are called properly. The biggest difference I can see is that
    > their PageViewCollection is derived from ControlCollection, while my
    > TabCollection is derived from CollectionBase. But I can't see how
    > that could be causing the problems.
    >
    > I really appreciate the help, Brock.
    >
    > Lisa
    >
     
    Brock Allen, May 12, 2005
    #7
  8. Guest

    Brock, thank you! I didn't find the answer from these links, but they
    helped me figure out what the problem was.

    I think the fact that the content of the Tabs are children of the Tabs
    *is* the problem. If the application sees those controls as children
    of the Tabs, and the Tabs as children of the TabControl, there's no way
    the app will see the events or postback data of the children unless
    it's raised explicitly.

    The content of the Tabs needs to be rendered by the TabControl, but it
    can't be a part of the TabControl in terms of the control hierarchy.

    So now I have a different problem, and maybe it's more easily solved.
    On the one hand, I need to be able to access the contents of the Tabs
    during Render so that I can render them, but on the other hand, I can't
    have them be children of the Tabs. Is there any way in the world that
    I can accomplish that?

    Thanks again,
    Lisa



    Brock Allen wrote:
    > Sorry Lisa, I can't quite tell exactly what the problem is from this.

    What
    > I'd suggest is to build a small sample outside of your current

    project that
    > works the way you want it and then try to compare the differences.

    Here are
    > some samples that might get you started:
    >
    >

    http://msdn.microsoft.com/library/d...stomizingcontrolswithtemplates.asp?frame=true
    >
    >

    http://winfx.msdn.microsoft.com/lib...html/986f63b8-6b50-42b9-a62d-a2f13cafa88b.asp
    >
    > And more of the same here:
    >
    >

    http://samples.gotdotnet.com/quicks.../quickstart/aspplus/doc/webctrlauthoring.aspx
    >
    > -Brock
    > DevelopMentor
    > http://staff.develop.com/ballen
    >
    >
    >
    > > Brock Allen wrote:
    > >
    > >>> It's a bit long, but here it is. I appreciate the help.
    > >>>
    > >> Ugg, I should have said "post the smallest amount of code that
    > >>

    > > reproduces
    > >
    > >> the problem".
    > >>

    > > I'm sorry. I honestly wasn't sure what part that would be.

    Although
    > > I suppose I could have left out the designer. <sheepish grin>
    > >
    > >> Ok, so I skimmed the code and, IIRC, your problem is that declared
    > >>

    > > controls
    > >
    > >> aren't getting server side events called? I think past of the

    problem
    > >>

    > > is
    > >
    > >> that the controls aren't part of the control hierarchy... meaning,

    I
    > >>

    > > don't
    > >
    > >> see where the controls that are in the TabdCollection are ever

    added
    > >>

    > > into
    > >
    > >> the control tree. If they're not in the control tree then they

    miss
    > >>

    > > out on
    > >
    > >> a lot of the server side processing. Again, that was a huge code
    > >>

    > > dump, so
    > >
    > >> my quick glance at it might be off.
    > >>

    > > I apologize for the size, Brock. Here is what it looks like in the
    > > HTML at design time:
    > >
    > > <fw:TabControl id="TabControl1" runat="server">
    > > <fw:Tab ID="TabControl1__ctl0" Text="Tab 1">&nbsp;</fw:Tab>
    > > <fw:Tab ID="TabControl1__ctl1" Text="Tab 2">
    > > <asp:Button id="Button1" runat="server" Text="Button" />
    > > </fw:Tab>
    > > </fw:TabControl>
    > > When I dragged it onto the form and added two tabs, it looked just
    > > like this, except that there was a non-breaking space where the

    button
    > > is.
    > >
    > > When I'm in run time, I see this in the Command Window:
    > >
    > > ?me.Tabs(1).Controls(1).ID
    > > "Button1"
    > > "Me", in this case, is the TabControl. Maybe I don't understand

    the
    > > control hierarchy, but doesn't the fact that I can reference the
    > > button at run time this way mean that the button is part of the
    > > control hierarchy?
    > >
    > > In terms of how the Tabs themselves are added, the TabCollection

    has
    > > this:
    > >
    > > Public Sub Add(ByVal myTab As Tab)
    > > MyBase.List.Add(myTab)
    > > End Sub 'Add
    > > And the TabControl has this in global declarations:
    > >
    > > Private _tabs As New TabCollection
    > >
    > > And it has this property:
    > >
    > > Public ReadOnly Property Tabs() As TabCollection
    > > Get
    > > Return _tabs
    > > End Get
    > > End Property
    > > Assuming that that's all the relevant code (which I'm unsure of),

    do
    > > you see what could be causing my problem? Since the Button is

    already
    > > visible at run time as a child of the second tab, I don't know what

    I
    > > could add the Button to without it creating a second Button.
    > >
    > > The Microsoft Multipage control works the same way. I can add a
    > > Button (let's say) between the start and end tags of a PageView
    > > control (analogous to my Tab control), and somehow, the Button's
    > > events are called properly. The biggest difference I can see is

    that
    > > their PageViewCollection is derived from ControlCollection, while

    my
    > > TabCollection is derived from CollectionBase. But I can't see how
    > > that could be causing the problems.
    > >
    > > I really appreciate the help, Brock.
    > >
    > > Lisa
    > >
     
    , May 13, 2005
    #8
    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. Andreas Klemt
    Replies:
    0
    Views:
    483
    Andreas Klemt
    Jul 4, 2003
  2. Jeff Rodriguez
    Replies:
    23
    Views:
    1,200
    David Schwartz
    Dec 9, 2003
  3. Mr. SweatyFinger
    Replies:
    2
    Views:
    2,220
    Smokey Grindel
    Dec 2, 2006
  4. Replies:
    7
    Views:
    464
  5. ss yy via .NET 247

    Events don't trigger

    ss yy via .NET 247, Aug 30, 2004, in forum: ASP .Net Web Services
    Replies:
    0
    Views:
    153
    ss yy via .NET 247
    Aug 30, 2004
Loading...

Share This Page