2

I want to add a new set of .net controls and html tags when a button is clicked.

At this moment I have a placeholder where I'm adding controls dynamically from code behind in VB.Net and it is right done but, whenever there is a postback (when a button is clicked or a dropdown is changed its value) they are not re-generated. Which is the right way to maintain these elements?

I have searched in these pages (msd, stackoverflow1 stackoverflow2 ) but it just show "how to add" but no "how to maintain" controls Below is my code if you could help me: This is the aspx:

<asp:PlaceHolder ID="reportFields" runat="server"></asp:PlaceHolder>

And this is the code Behind:

Private Sub generatenewReportField(count As Integer)
    reportFields.Controls.Add(New LiteralControl("<div class=""col-sm-12"">"))
    'Name field
    reportFields.Controls.Add(New LiteralControl("<div class=""form-group col-sm-3"">"))
    reportFields.Controls.Add(New LiteralControl("<label for=""txtNewFieldName" & count & """>Name</label>"))
    Dim tx1 As New TextBox()
    tx1.CssClass = "form-control input-sm"
    tx1.ID = "txtNewFieldName" & count
    tx1.ToolTip = "New Field Name"
    reportFields.Controls.Add(tx1)
    reportFields.Controls.Add(New LiteralControl("</div>"))

    'formula field
    reportFields.Controls.Add(New LiteralControl("<div class=""form-group col-sm-3"">"))
    reportFields.Controls.Add(New LiteralControl("<label for=""txtNewFieldFormula" & count & """>Formula</label>"))
    Dim tx2 As New TextBox()
    tx2.CssClass = "form-control input-sm"
    tx2.ID = "txtNewFieldFormula" & count
    tx2.ToolTip = "New Field Formula"
    reportFields.Controls.Add(tx2)
    reportFields.Controls.Add(New LiteralControl("</div>"))

    'isKPI?
    reportFields.Controls.Add(New LiteralControl("<div class=""form-group col-sm-2"">"))
    reportFields.Controls.Add(New LiteralControl("<label for=""chkKPI" & count & """>Is KPI</label><br/>"))
    Dim isKPI As New CheckBox
    isKPI.CssClass = " switch input-sm"
    isKPI.ID = "chkKPI" & count
    initializeSwitch()
    reportFields.Controls.Add(isKPI)
    reportFields.Controls.Add(New LiteralControl("</div>"))

    'KPI Weight
    reportFields.Controls.Add(New LiteralControl("<div class=""form-group col-sm-3"">"))
    reportFields.Controls.Add(New LiteralControl("<label for=""txtNewFieldKPIWeight" & count & """>Weight</label>"))
    Dim tx3 As New TextBox()
    tx3.CssClass = "form-control input-sm"
    tx3.ID = "txtNewFieldKPIWeight" & count
    reportFields.Controls.Add(tx3)
    reportFields.Controls.Add(New LiteralControl("</div>"))
    reportFields.Controls.Add(New LiteralControl("</div>"))
    reportFields.Controls.Add(New LiteralControl("<br/>"))
End Sub

Tanks for the help!

Community
  • 1
  • 1
dfsotop
  • 31
  • 5
  • Possible duplicate of [How to persist a dynamic control (c#)](http://stackoverflow.com/questions/5567707/how-to-persist-a-dynamic-control-c) – T.S. Feb 04 '17 at 01:57
  • You should use word "preserve" when you talk of food or natural resources. In software we use word "persist", or "maintain", or "restore" – T.S. Feb 04 '17 at 01:59
  • @T.S. Thanks for the advice. I'm sorry, I'm not English native speaker, but I am continuously learning. spelling changed – dfsotop Feb 06 '17 at 14:00

3 Answers3

1

I have found the answer based on @Hammer125 comment and my own research. It's all about using updatePanel. This link should help msdn. Using update panel in aspx.

I created two update panels. the first one is where the user sets the values of the new elements and the second one is where those are showed. For my purposes I used here a gridview for show and handle the generated values. However this gridview could be replaced for whatever control wanted. Besides I also made an object with the properties I want to save.

This is the aspx.

<div class="col-md-12 well">
                    <asp:UpdatePanel ID="updPanelNewField" runat="server" UpdateMode="Conditional">
                        <ContentTemplate>
                            <div class="col-sm-12">
                                <div class="form-group col-sm-3">
                                    <label for="txtNewName">Name</label>
                                    <asp:TextBox runat="server" ID="txtNewName" CssClass="form-control input-sm" ToolTip="Field's name"></asp:TextBox>
                                </div>
                                <div class="form-group col-sm-3">
                                    <label for="txtNewFormula">Formula</label>
                                    <asp:TextBox runat="server" ID="txtNewFormula" CssClass="form-control input-sm" ToolTip="Field's formula"></asp:TextBox>
                                </div>
                                <div class="form-group col-sm-2">
                                    <label for="chkNewKPI">is KPI</label><br />
                                    <asp:CheckBox runat="server" ID="chkNewKPI" CssClass="input-sm"/>
                                </div>
                                <div class="form-group col-sm-3">
                                    <label for="txtNewWeight">KPI Weight</label>
                                    <asp:TextBox runat="server" ID="txtNewWeight" CssClass="form-control input-sm" ToolTip="KPI's Weight (Remember don't pass 100% ;) ) "></asp:TextBox>
                                </div>
                                <div class="form-group col-sm-1 text-center" style="padding-left:1em; padding-top:1em">
                                    <asp:Button runat="server" ID="addNewField" CssClass="btn btn-primary" Width="2em" Height="2em" Text="+" Font-Bold="true" Font-Size="Large" />
                                </div>
                            </div>
                        </ContentTemplate>
                    </asp:UpdatePanel>
                    <hr />
                    <asp:UpdatePanel ID="UpdatePanel1" runat="server" UpdateMode="Conditional">
                        <ContentTemplate>
                            <asp:GridView ID="gdvFields" runat="server" CellPadding="1" GridLines="Horizontal">
                                <Columns>
                                    <asp:BoundField DataField ="Id" HeaderText="ID"/>
                                    <asp:BoundField DataField="Name" HeaderText="Name"/>
                                    <asp:BoundField DataField="Formula" HeaderText="Formula" />
                                    <asp:CommandField HeaderText="Options" CausesValidation="true" ShowDeleteButton="true" ShowEditButton="true"/> 
                                </Columns>
                                <PagerSettings PageButtonCount="10" />
                            </asp:GridView>
                        </ContentTemplate>
                        <Triggers>
                        <asp:AsyncPostBackTrigger ControlID="addNewField" EventName="Click" />
                    </Triggers>
                    </asp:UpdatePanel>
                </div>

This is the new class I added to the code:

<Serializable()> _
Public Class ReportField

Private _id As Integer
Private _name As String
Private _formula As String
Sub New(fieldId As Integer, fieldName As String, fieldFormula As String)
    _id = fieldId
    _name = fieldName
    _formula = fieldFormula
End Sub

Public Property id() As Integer
    Get
        Return _id
    End Get
    Set(ByVal value As Integer)
        _id = value
    End Set
End Property


Public Property name() As String
    Get
        Return _name
    End Get
    Set(ByVal value As String)
        _name = value
    End Set
End Property

Public Property formula() As String
    Get
        Return _formula
    End Get
    Set(ByVal value As String)
        _formula = value
    End Set
End Property

Private _isKPI As Boolean
Public Property isKPI() As Boolean
    Get
        Return _isKPI
    End Get
    Set(ByVal value As Boolean)
        _isKPI = value
    End Set
End Property

Private _KPIWeight As Integer
Public Property KPIWeight() As Integer
    Get
        Return _KPIWeight
    End Get
    Set(ByVal value As Integer)
        _KPIWeight = value
    End Set
End Property
End Class

And this is the code behind where I make it works:

#Region "Variables"
Dim count As Integer
Private thisReportFieldsList As List(Of ReportField)
#End Region
#Region "Events"

Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
    Try
        If Not IsPostBack() Then
            count = 1
            thisReportFieldsList = New List(Of ReportField)
            ViewState("reportFieldsList") = thisReportFieldsList
        Else
            thisReportFieldsList = CType(ViewState("reportFieldsList"), List(Of ReportField))
        End If

        gdvFields.DataSource = thisReportFieldsList
        gdvFields.DataBind()

    Catch ex As Exception
        showError(ex.Message)
    End Try

End Sub

Protected Sub addNewField_Click(sender As Object, e As EventArgs) Handles addNewField.Click
    Try
        If String.IsNullOrEmpty(txtNewName.Text) Or String.IsNullOrEmpty(txtNewFormula.Text) Then
            showError("Please add at least the name and formula of the new field", "Field not added")
            Return
        End If
        Dim id As Integer
        If thisReportFieldsList.Count = 0 Then
            id = 0
        Else
            id = thisReportFieldsList(thisReportFieldsList.Count - 1).id
        End If
        Dim fieldId As Integer = id + 1
        Dim fieldName As String = Server.HtmlEncode(txtNewName.Text)
        Dim fieldFormula As String = Server.HtmlEncode(txtNewFormula.Text)
        txtNewName.Text = String.Empty
        txtNewFormula.Text = String.Empty
        thisReportFieldsList.Add(New ReportField(fieldId, fieldName, fieldFormula))
        ViewState("reportFieldsList") = thisReportFieldsList
        gdvFields.DataBind()
        gdvFields.PageIndex = gdvFields.PageCount
    Catch ex As Exception
        showError(ex.Message)
    End Try
End Sub
#End Region

I hope I had made myself explained well and this helps to someone

dfsotop
  • 31
  • 5
1

Call the generateReportField() method from the Pre_Init even for your page. You need to do this on every postback, because every postback is using a whole new instance of your page class, and you need to do it before ViewState is loaded at the Init phase, or ViewState won't work correctly for those controls.

Joel Coehoorn
  • 399,467
  • 113
  • 570
  • 794
-1

You could solve the problem by adding Partial Postback, which only refreshes a part of a page. That way, you can request an update to a part of the page that needs to change and leave those you don't want the way they are. You can do that by using the UpdatePanel control.

Some links that can help:

Hammer125
  • 31
  • 1
  • 5