Click here to Skip to main content
15,886,137 members
Articles / Web Development / ASP.NET

Auto save/load template server control for the ASP.NET Controls collection

Rate me:
Please Sign up or sign in to vote.
4.55/5 (17 votes)
5 Sep 2008CPOL5 min read 48.4K   429   31  
An ASP.NET template server control demonstrating how we can store/retrieve values of various ASP.NET controls on a page.
Option Strict On
Imports System
Imports System.ComponentModel
Imports System.Drawing
Imports System.Security.Permissions
Imports System.Web
Imports System.Web.UI
Imports System.Web.UI.WebControls
Imports System.Web.UI.Design


<AspNetHostingPermission(SecurityAction.Demand, _
        Level:=AspNetHostingPermissionLevel.Minimal), _
    AspNetHostingPermission(SecurityAction.InheritanceDemand, _
        Level:=AspNetHostingPermissionLevel.Minimal), _
    Designer(GetType(SmartFilterDesigner)), _
    DefaultProperty("Title"), _
    ToolboxData( _
        "<{0}:SmartFilter runat=""server""> </{0}:SmartFilter>") _
    > _
    Public Class SmartFilter
    Inherits CompositeControl
    Private _template As ITemplate
    Private _owner As TemplateOwner

    < _
    Bindable(True), _
    Category("Data"), _
    DefaultValue(""), _
    Description("Caption") _
    > _
    Public Overridable Property Caption() As String
        Get
            Dim s As String = CStr(ViewState("Caption"))
            If s Is Nothing Then s = String.Empty
            Return s
        End Get
        Set(ByVal value As String)
            ViewState("Caption") = value
        End Set
    End Property

    < _
    Browsable(False), _
    DesignerSerializationVisibility( _
        DesignerSerializationVisibility.Hidden) _
    > _
    Public ReadOnly Property Owner() As TemplateOwner
        Get
            Return _owner
        End Get
    End Property

    < _
    Browsable(False), _
    PersistenceMode(PersistenceMode.InnerProperty), _
    DefaultValue(GetType(ITemplate), ""), _
    Description("Control template"), _
    TemplateContainer(GetType(SmartFilter)) _
    > _
    Public Overridable Property Template() As ITemplate
        Get
            Return _template
        End Get
        Set(ByVal value As ITemplate)
            _template = value
        End Set
    End Property

    < _
    Bindable(True), _
    Category("Data"), _
    DefaultValue(""), _
    Description("Title"), _
    Localizable(True) _
    > _
    Public Property Title() As String
        Get
            Dim s As String = CStr(ViewState("Title"))
            If s Is Nothing Then s = String.Empty
            Return s
        End Get
        Set(ByVal value As String)
            ViewState("Title") = value
        End Set
    End Property


    Protected Overrides Sub CreateChildControls()
        Controls.Clear()
        _owner = New TemplateOwner()

        Dim temp As ITemplate = _template
        If temp Is Nothing Then
            temp = New DefaultTemplate
        End If

        temp.InstantiateIn(_owner)
        Me.Controls.Add(_owner)
    End Sub

    Public Overrides Sub DataBind()

        If Not ChildControlsCreated Then
            CreateChildControls()
            ChildControlsCreated = True
        End If
        MyBase.DataBind()

    End Sub


    Protected Overrides Sub Finalize()
        MyBase.Finalize()
    End Sub

    Private Sub SmartFilter_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load

        'This is where all the logic resides
        'If this is NOT a post back we are getting values from session, we will have to change the code to read values from database instead
        'the database will have 5 columns FormId, Control Id, control type, control value and user id
        'For the logged in user (get user id from the context like grid control). Pass the user id and form id to the database which will return 
        ' 3 columns control id, control type and control value for selected combination
        'then loop through the code to read the values from databaset and load them into control. This code is already there.

        'If this is a post back then we need to loop through the controls, read the user selections and send them to database for storing into 
        'profile table so that they can be loaded next time.
        If Not Me.Page.IsPostBack Then

            LoadControlValuesFromProfile()

        Else

            StoreControlValuesToProfile()
        End If
    End Sub

    ' This part of the code can have some more improvements, this can be modified to make sure that the post back done by the page was initiated by search 
    ' button and not some other event. This way we will not store the user's filter criteria on each post back and we can save it only when search is
    ' clicked when there is chance of user changing his search parameters. As soon as this part is done I'll send you guys new code. 
    ' For now the code will work even without this in place just that for each post back we will make a call to database and store the search criterias
    ' for the user
    Private Function GetPostBackControl(ByVal page As Page) As Control

        Dim postbackControlInstance As Control = Nothing
        Dim postbackControlName As String = page.Request.Params.[Get]("__EVENTTARGET")

        If postbackControlName <> Nothing AndAlso postbackControlName <> String.Empty Then
            postbackControlInstance = page.FindControl(postbackControlName)
        Else
            ' handle the Button control postbacks

            Dim i As Integer = 0
            While i < page.Request.Form.Keys.Count

                postbackControlInstance = page.FindControl(page.Request.Form.Keys(i))
                If TypeOf postbackControlInstance Is System.Web.UI.WebControls.Button Then
                    Return postbackControlInstance
                End If
                System.Math.Max(System.Threading.Interlocked.Increment(i), i - 1)
            End While
        End If

        ' handle the ImageButton postbacks
        If postbackControlInstance Is Nothing Then
            Dim i As Integer = 0
            While i < page.Request.Form.Count
                If (page.Request.Form.Keys(i).EndsWith(".x")) OrElse (page.Request.Form.Keys(i).EndsWith(".y")) Then
                    postbackControlInstance = page.FindControl(page.Request.Form.Keys(i).Substring(0, page.Request.Form.Keys(i).Length - 2))
                    Return postbackControlInstance
                End If
                System.Math.Max(System.Threading.Interlocked.Increment(i), i - 1)
            End While
        End If
        Return postbackControlInstance
    End Function


    Private Sub LoadControlValuesFromProfile()
        If Not IsNothing(HttpContext.Current.Session(Me.Page.Form.ID)) Then

            ' If child controls are not created yet then create.
            If Not ChildControlsCreated Then
                CreateChildControls()
                ChildControlsCreated = True
            End If

            ' Get value from datasource for filter control.
            Dim objArray As ArrayList
            objArray = CType(HttpContext.Current.Session(Me.Page.Form.ID), ArrayList)

            For Each objControl In objArray

                Dim objControlInfo As ArrayList = CType(objControl, ArrayList)

                ' populate filter control with history data.
                Select Case objControlInfo(0).ToString
                    Case "textbox"
                        CType(_owner.FindControl(objControlInfo(1).ToString), TextBox).Text = objControlInfo(2).ToString
                    Case "dropdownlist"
                        CType(_owner.FindControl(objControlInfo(1).ToString), DropDownList).SelectedValue = objControlInfo(2).ToString
                    Case "checkbox"
                        CType(_owner.FindControl(objControlInfo(1).ToString), CheckBox).Checked = CType(objControlInfo(2).ToString, Boolean)
                    Case "radiobutton"
                        CType(_owner.FindControl(objControlInfo(1).ToString), RadioButton).Checked = CType(objControlInfo(2).ToString, Boolean)
                    Case Else
                        ' Do nothing.
                End Select
            Next
        End If

    End Sub


    Private Sub StoreControlValuesToProfile()

        ' Insert data into datasource from filter control.
        Dim objArray As New ArrayList

        For Each objControl In _owner.Controls

            Dim objControlInfo As New ArrayList
            Select Case objControl.GetType.Name.ToLower()
                Case "textbox"
                    objControlInfo.Add("textbox")
                    objControlInfo.Add(CType(objControl, WebControl).ID)
                    objControlInfo.Add(CType(objControl, TextBox).Text)
                Case "dropdownlist"
                    objControlInfo.Add("dropdownlist")
                    objControlInfo.Add(CType(objControl, WebControl).ID)
                    objControlInfo.Add(CType(objControl, DropDownList).SelectedValue)
                Case "checkbox"
                    objControlInfo.Add("checkbox")
                    objControlInfo.Add(CType(objControl, WebControl).ID)
                    objControlInfo.Add(CType(objControl, CheckBox).Checked.ToString)
                Case "radiobutton"
                    objControlInfo.Add("radiobutton")
                    objControlInfo.Add(CType(objControl, WebControl).ID)
                    objControlInfo.Add(CType(objControl, RadioButton).Checked.ToString)
                Case Else
                    ' Do nothing
            End Select
            If objControlInfo.Count <> 0 Then
                objArray.Add(objControlInfo)
            End If
        Next

        HttpContext.Current.Session(Me.Page.Form.ID) = objArray

    End Sub

End Class


<ToolboxItem(False)> _
Public Class TemplateOwner
    Inherits WebControl
End Class

#Region "DefaultTemplate"
NotInheritable Class DefaultTemplate
    Implements ITemplate

    Sub InstantiateIn(ByVal owner As Control) _
        Implements ITemplate.InstantiateIn
        Dim title As New Label
        AddHandler title.DataBinding, AddressOf title_DataBinding
        Dim linebreak As New LiteralControl("<br/>")
        Dim caption As New Label
        AddHandler caption.DataBinding, _
            AddressOf caption_DataBinding
        owner.Controls.Add(title)
        owner.Controls.Add(linebreak)
        owner.Controls.Add(caption)

        For Each objControl In owner.Controls
            ' = objControl.ToString

        Next
    End Sub

    Sub caption_DataBinding(ByVal sender As Object, _
        ByVal e As EventArgs)
        Dim source As Label = CType(sender, Label)
        Dim container As SmartFilter = _
            CType(source.NamingContainer, SmartFilter)
        source.Text = container.Caption
    End Sub


    Sub title_DataBinding(ByVal sender As Object, _
        ByVal e As EventArgs)
        Dim source As Label = CType(sender, Label)
        Dim container As SmartFilter = _
            CType(source.NamingContainer, SmartFilter)
        source.Text = container.Caption
    End Sub
End Class
#End Region


Public Class SmartFilterDesigner
    Inherits ControlDesigner

    Public Overrides Sub Initialize(ByVal Component As IComponent)
        MyBase.Initialize(Component)
        SetViewFlags(ViewFlags.TemplateEditing, True)
    End Sub

    Public Overloads Overrides Function GetDesignTimeHtml() As String
        Return "<span>This is design-time HTML</span>"
    End Function

    Public Overrides ReadOnly Property TemplateGroups() As TemplateGroupCollection
        Get
            Dim collection As New TemplateGroupCollection
            Dim group As TemplateGroup
            Dim template As TemplateDefinition
            Dim control As SmartFilter

            control = CType(Component, SmartFilter)
            group = New TemplateGroup("Item")
            template = New TemplateDefinition(Me, "Template", control, "Template", True)
            group.AddTemplateDefinition(template)
            collection.Add(group)
            Return collection
        End Get
    End Property
End Class


By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Architect L&T Infotech
India India
Vishal has over 17 years of IT experience with over 15 years on Microsoft technologies from QW Basic to .net 4.5. Vishal works as a Lead Architect for the L&T Infotech. He has given various presentaions at code camps, Teched Tweener and various user group events.
Winner of INETA Community Champions award for 2008 Q3.
Microsoft VB .Net MVP 2009-2011

Comments and Discussions