Persist viewstate in ITemplate child controls

G

George

Hello Coders,

I have a particularly brain frying problem today. I'd appreciate it if you
can help before I test how strong the walls of the office are.

I have been building a custom collapsible panel control, into which I'm
placing some custom web user controls. The viewstate of my custom
webcontrols is not persisting between postbacks. I think this is because
inside my collapsible panel, I override CreateChildControls (to layout my
controls from my ITemplate) and OnInit (to call EnsureChildControls).

I'm attaching the code for my panel (which I have been poking at for nearly
2 days to get working).

Sorry, but this is long. This important parts you would want to look at are
inside the 'Overrides' region.

Many thanks.

Imports System
Imports System.Collections.Generic
Imports System.ComponentModel
Imports System.Text
Imports System.Web
Imports System.Web.UI
Imports System.Web.UI.WebControls
Imports System.Web.UI.Design.WebControls

Namespace Curve.WebControls

<DefaultProperty("Text")> _
<ToolboxData("<{0}:CollapsingPanel
runat=server></{0}:CollapsingPanel>")> _
<Designer(GetType(CollapsingPanelDesigner))> _
<ParseChildren(True)> _
Public Class CollapsingPanel
Inherits Panel
Implements INamingContainer

Public Event CloseButtonClicked(ByRef self As CollapsingPanel)

#Region " Variables "

Private header As ITemplate
Private content As ITemplate

Private headerTemplateContainer As New
CollapsingPanelTemplateContainer
Private contentTemplateContainer As New
CollapsingPanelTemplateContainer

Private updatePanel As New UpdatePanel

Private collapseStateTextBox As New TextBox

Private expandAnimation As New AjaxControlToolkit.AnimationExtender
Private collapseAnimation As New
AjaxControlToolkit.AnimationExtender

Private mainPanel As New Panel
Private titlePanel As New Panel
Private bodyPanel As New Panel
Private bodyInnerPanel As New Panel
Private titleLabel As New Label
Private refreshButton As New ImageButton
Private collapseButton As New ImageButton
Private expandButton As New ImageButton
Private closeButton As New ImageButton
Private titleTable As New Table
Private tr As New TableRow
Private titleLabelCell As New TableCell
Private titleButtonsCell As New TableCell
Private refreshSpacer As New LiteralControl(" ")
Private collapseSpacer As New LiteralControl(" ")
Private closeSpacer As New LiteralControl(" ")

#End Region

#Region " Properties "

<Bindable(True)> _
<PersistenceMode(PersistenceMode.InnerProperty)> _
<TemplateContainer(GetType(CollapsingPanelTemplateContainer))> _
<TemplateInstance(TemplateInstance.Single)> _
Public Property HeaderTemplate() As ITemplate
Get
Return header
End Get
Set(ByVal value As ITemplate)
header = value
End Set
End Property

<Browsable(False)> _
<PersistenceMode(PersistenceMode.InnerProperty)> _
<TemplateContainer(GetType(CollapsingPanelTemplateContainer))> _
<TemplateInstance(TemplateInstance.Single)> _
Public Property ContentTemplate() As ITemplate
Get
Return content
End Get
Set(ByVal value As ITemplate)
content = value
End Set
End Property

<Bindable(True)> _
<Category("Appearance")> _
<DefaultValue("")> _
<Localizable(True)> _
Public Property Title() As String
Get
Dim s As String = ViewState("Title")
Return IIf(s = Nothing, String.Empty, s)
End Get
Set(ByVal value As String)
ViewState("Title") = value
If titleLabel IsNot Nothing Then
titleLabel.Text = value
End If
End Set
End Property

<Bindable(True)> _
<Category("Appearance")> _
<DefaultValue("")> _
<Localizable(True)> _
Public Property IsCollapsed() As Boolean
Get
Dim s As String = ViewState("IsCollapsed")
'Dim s As String = Me.Context.Items(Me.ID & "$IsCollapsed")
Return IIf(s = Nothing, False, Convert.ToBoolean(s))
End Get
Set(ByVal value As Boolean)
ViewState("IsCollapsed") = value.ToString
End Set
End Property

<Bindable(True)> _
<Category("Appearance")> _
<DefaultValue("")> _
<Localizable(True)> _
Public Property IsCollapsible() As Boolean
Get
Dim s As String = ViewState("IsCollapsible")
Return IIf(s = Nothing, False, Convert.ToBoolean(s))
End Get
Set(ByVal value As Boolean)
ViewState("IsCollapsible") = value.ToString
End Set
End Property

<Bindable(True)> _
<Category("Appearance")> _
<DefaultValue("")> _
<Localizable(True)> _
Public Property IsRefreshable() As Boolean
Get
Dim s As String = ViewState("IsRefreshable")
Return IIf(s = Nothing, False, Convert.ToBoolean(s))
End Get
Set(ByVal value As Boolean)
ViewState("IsRefreshable") = value
If refreshButton IsNot Nothing Then
refreshButton.Visible = value
End If
End Set
End Property

<Bindable(True)> _
<Category("Appearance")> _
<DefaultValue("")> _
<Localizable(True)> _
Public Property IsClosable() As Boolean
Get
Dim s As String = ViewState("IsClosable")
Return IIf(s = Nothing, False, Convert.ToBoolean(s))
End Get
Set(ByVal value As Boolean)
ViewState("IsClosable") = value.ToString
If closeButton IsNot Nothing Then
closeButton.Visible = value
End If
End Set
End Property

<Bindable(True)> _
<Category("Appearance")> _
<DefaultValue("")> _
<Localizable(True)> _
Public Property IsChildViewStateEnabled() As Boolean
Get
Dim s As String = ViewState("IsChildViewStateEnabled")
Return IIf(s = Nothing, True, Convert.ToBoolean(s))
End Get
Set(ByVal value As Boolean)
ViewState("IsChildViewStateEnabled") = value
End Set
End Property

#End Region

#Region " Overrides "

Protected Overrides Sub LoadViewState(ByVal savedState As Object)
MyBase.LoadViewState(savedState)
End Sub

Protected Overrides Function SaveViewState() As Object
Return MyBase.SaveViewState()
End Function

Protected Overrides Sub OnInit(ByVal e As EventArgs)
'BuildControlHeirarchy()
EnsureChildControls()
InitialiseControls()

If collapseStateTextBox.Text = "True" Then
Me.CollapsePanel()
Else
Me.OpenPanel()
End If
MyBase.OnInit(e)
End Sub

Protected Overrides Sub CreateChildControls()

CreateControlHeirarchy()

' Disable viewstate in all controls?
'If Not IsChildViewStateEnabled Then
' DisableViewState(Me)
'End If

' Set all the values and properties
'ConfigureInternalLayoutControls()
End Sub

'Protected Overrides Sub Render(ByVal writer As HtmlTextWriter)

' ' This anchor is used to allow a given collapsing panel to be
' ' navigated to on the page
' Dim anchor As New LiteralControl(String.Format("<a
name='{0}_anchor'></a>", ID))
' anchor.RenderControl(writer)
' 'mainPanel.RenderControl(writer)
' updatePanel.RenderControl(writer)

'End Sub

Public Overrides ReadOnly Property Controls() As ControlCollection
Get
Return MyBase.Controls
End Get
End Property

#End Region

#Region " Events "

Public Sub refreshButton_Click(ByVal sender As Object, ByVal e As
ImageClickEventArgs)
updatePanel.Update()
End Sub

Protected Sub closeButton_Click(ByVal sender As Object, ByVal e As
ImageClickEventArgs)
RaiseEvent CloseButtonClicked(Me)
End Sub

#End Region

#Region " Custom Methods "

Private Sub CreateControlHeirarchy()
Controls.Add(updatePanel)
updatePanel.ContentTemplateContainer.Controls.Add(mainPanel)
mainPanel.Controls.Add(collapseStateTextBox)
mainPanel.Controls.Add(titlePanel)
titlePanel.Controls.Add(titleTable)
titleTable.Rows.Add(tr)
tr.Cells.Add(titleLabelCell)
titleLabelCell.Controls.Add(headerTemplateContainer)

If HeaderTemplate IsNot Nothing Then
HeaderTemplate.InstantiateIn(headerTemplateContainer)
If headerTemplateContainer.Controls.Count <= 1 Then
headerTemplateContainer.Controls.Add(titleLabel)
End If

tr.Cells.Add(titleButtonsCell)
titleButtonsCell.Controls.Add(refreshSpacer)
titleButtonsCell.Controls.Add(refreshButton)
titleButtonsCell.Controls.Add(collapseSpacer)
titleButtonsCell.Controls.Add(collapseButton)
titleButtonsCell.Controls.Add(collapseAnimation)
titleButtonsCell.Controls.Add(expandButton)
titleButtonsCell.Controls.Add(expandAnimation)
titleButtonsCell.Controls.Add(closeSpacer)
titleButtonsCell.Controls.Add(closeButton)
mainPanel.Controls.Add(bodyPanel)
bodyPanel.Controls.Add(bodyInnerPanel)

' Add controls to bodyInnerPanel
contentTemplateContainer = New CollapsingPanelTemplateContainer
bodyInnerPanel.Controls.Add(contentTemplateContainer)
If ContentTemplate IsNot Nothing Then
ContentTemplate.InstantiateIn(contentTemplateContainer)
End If
End Sub

Private Sub InitialiseControls()
updatePanel.UpdateMode = UpdatePanelUpdateMode.Conditional

mainPanel.CssClass = "panel_container_group"
mainPanel.Width = Me.Width
bodyPanel.Width = Me.Width
bodyPanel.Height = Me.Height
'bodyPanel.ScrollBars = Me.ScrollBars

titlePanel.CssClass = "panel_container_header"
titleTable.Width = New Unit(100, UnitType.Percentage)

titleLabel.Text = Title

titleButtonsCell.HorizontalAlign = HorizontalAlign.Right
titleButtonsCell.VerticalAlign = VerticalAlign.Middle

refreshSpacer.Visible = IsRefreshable
refreshButton.ImageUrl =
"~/client/site_layout/icons/container_refresh.png"
AddHandler refreshButton.Click, AddressOf Me.refreshButton_Click
refreshButton.Visible = IsRefreshable

collapseSpacer.Visible = IsCollapsible
collapseButton.ImageUrl =
"~/client/site_layout/icons/container_collapse.png"
collapseButton.ToolTip = "Collapse"
collapseButton.Visible = IsCollapsible

collapseAnimation.TargetControlID = collapseButton.UniqueID
collapseAnimation.Animations = GetCollapseAnimationXml()

expandButton.ImageUrl =
"~/client/site_layout/icons/container_expand.png"
expandButton.ToolTip = "Expand"
expandButton.Visible = IsCollapsible

expandAnimation.TargetControlID = expandButton.UniqueID
expandAnimation.Animations = GetExpandAnimationXml()

If Not Me.Page.IsPostBack Then
collapseStateTextBox.Text = IsCollapsed
End If

If IsCollapsible Then
If IsCollapsed Then
collapseButton.Style("display") = "none"
expandButton.Style("display") = "inline"
bodyPanel.Style("display") = "none"
Else
collapseButton.Style("display") = "inline"
expandButton.Style("display") = "none"
bodyPanel.Style("display") = "block"
End If
End If

closeSpacer.Visible = IsClosable
closeButton.ImageUrl =
"~/client/site_layout/icons/container_close.png"
closeButton.ToolTip = "Close"
closeButton.OnClientClick = "return confirm('Are you sure you
want to close this panel?');"
AddHandler closeButton.Click, AddressOf Me.closeButton_Click
closeButton.Visible = IsClosable

'If CloseConfirmation IsNot Nothing AndAlso
CloseConfirmation.Trim <> "" Then
' closeButton.OnClientClick = "var close = confirm('" &
CloseConfirmation & "'); if (! close) {return false;}"
'End If

bodyPanel.CssClass = "panel_container"
bodyInnerPanel.CssClass = "panel_container_inner"

collapseStateTextBox.Style.Add("display", "none")
collapseStateTextBox.Visible = True
expandButton.Attributes.Add("onclick", String.Format("{0}.value
= 'False';return false;", collapseStateTextBox.ClientID))
collapseButton.Attributes.Add("onclick",
String.Format("{0}.value = 'True';return false;",
collapseStateTextBox.ClientID))
End Sub

''' <summary>
''' Recursive function to disable viewstate on control and all of
its children.
''' </summary>
''' <param name="c"></param>
''' <remarks></remarks>
Private Sub DisableViewState(ByVal c As Control)
'c.EnableViewState = False
'For Each sc As Control In c.Controls
' sc.EnableViewState = False
' If sc.HasControls Then
' DisableViewState(sc)
' End If
'Next
End Sub

Private Function GetCollapseAnimationXml() As String
Dim sb As New IO.StringWriter

sb.WriteLine("<OnClick>")
sb.WriteLine(" <Parallel Duration="".2"" Fps=""40"">")
sb.WriteLine(" <StyleAction AnimationTarget=""{0}""
Attribute=""display"" Value=""none"" />", collapseButton.UniqueID)
sb.WriteLine(" <StyleAction AnimationTarget=""{0}""
Attribute=""display"" Value=""inline"" />", expandButton.UniqueID)
sb.WriteLine(" <StyleAction AnimationTarget=""{0}""
Attribute=""display"" Value=""none"" />", bodyPanel.UniqueID)
sb.WriteLine(" </Parallel>")
sb.WriteLine("</OnClick>")

Return sb.ToString
End Function

Private Function GetExpandAnimationXml() As String
Dim sb As New IO.StringWriter

sb.WriteLine("<OnClick>")
sb.WriteLine(" <Parallel Duration="".2"" Fps=""40"">")
sb.WriteLine(" <StyleAction AnimationTarget=""{0}""
Attribute=""display"" Value=""none"" />", expandButton.UniqueID)
sb.WriteLine(" <StyleAction AnimationTarget=""{0}""
Attribute=""display"" Value=""inline"" />", collapseButton.UniqueID)
sb.WriteLine(" <StyleAction AnimationTarget=""{0}""
Attribute=""display"" Value=""block"" />", bodyPanel.UniqueID)
sb.WriteLine(" </Parallel>")
sb.WriteLine("</OnClick>")

Return sb.ToString
End Function

Public Sub Update()
updatePanel.Update()
End Sub

Public Sub CollapsePanel()
If IsCollapsible Then
collapseButton.Style("display") = "none"
expandButton.Style("display") = "inline"
bodyPanel.Style("display") = "none"
End If
End Sub

Public Sub OpenPanel()
If IsCollapsible Then
collapseButton.Style("display") = "inline"
expandButton.Style("display") = "none"
bodyPanel.Style("display") = "block"
End If
End Sub

#End Region

End Class

Public Class CollapsingPanelDesigner
Inherits PanelContainerDesigner

Private panel As CollapsingPanel

Public Overrides Sub Initialize(ByVal component As IComponent)
MyBase.Initialize(component)
panel = component
End Sub

Public Overrides ReadOnly Property FrameCaption() As String
Get
Return IIf(panel.Title Is Nothing Or panel.Title.Trim = "",
"Collapsible Panel", panel.Title)
End Get
End Property
End Class


<ViewStateModeById()> _
Public Class CollapsingPanelTemplateContainer
Inherits WebControl
Implements INamingContainer

'Private _parent As CollapsingPanel

'Public Sub New(ByVal Parent As CollapsingPanel)
' _parent = Parent
'End Sub

'Public ReadOnly Property CollapsingPanel() As CollapsingPanel
' Get
' Return _parent
' End Get
'End Property

End Class

End Namespace
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,744
Messages
2,569,482
Members
44,901
Latest member
Noble71S45

Latest Threads

Top