Where is my dynamic control after I submit the form? - asp.net

I created a dynamic form with a repeater.
<asp:repeater ID="fieldRepeater" OnItemDataBound="dataBound" runat="server">
<itemtemplate>
<div id="controlRow" class="row" runat="server">
<div id="testContainer" class="col-md-2" runat="server">
</div>
</div>
</itemtemplate>
</asp:repeater>
in codebehind I created the field I want to appear in it.
Protected Sub dataBound(ByVal sender As Object, e As RepeaterItemEventArgs)
dim temp as new DropDownList
dim tempLabel as new label
Dim testContainer As HtmlGenericControl = e.Item.FindControl("testContainer")
'createField
temp.ID = "testField" & e.Item.ItemIndex 'this is testField0
temp.Items.Add(New ListItem("Not Used", 0))
temp.Items.Add(New ListItem("Used", 1))
temp.CssClass = "form-control"
'createLabel
tempLabel.ID = "testFieldLabel" & e.Item.ItemIndex
tempLabel.AssociatedControlID = "testField" & e.Item.ItemIndex
tempLabel.Text = dr("controlLabel")
testContainer.Controls.Add(temp)
testContainer.Controls.Add(tempLabel)
end sub
The form works beautifully and I can even pre-populate it with data from a db, but in my submit handler my controls don't exist:
Protected Sub submit_Click(ByVal sender As Object, ByVal e As EventArgs) Handles submit.Click
Dim i As Int32 = 0
For Each r As DataRow ...
'db stuff
Dim temp As New DropDownList
temp = Me.FindControl("testField" & i.ToString)
'db stuff
i += 1
next
end sub
temp = Me.FindControl("testField" & i.ToString) is always nothing Can someone help me find out why?
My HTML output looks like:
<div id="cntMain_fieldRepeater_testContainer_0" class="col-md-2">
<label for="cntMain_fieldRepeater_testField0_0" id="cntMain_fieldRepeater_testFieldLabel0_0" style="color:#007AFF;">Activity</label>
<select name="ctl00$cntMain$fieldRepeater$ctl00$testField0" id="cntMain_fieldRepeater_testField0_0" class="form-control">
<option value="0">Not Used</option>
<option value="1">Used</option>
</select>
</div>

Dynamically created Controls need to be (re)created on every Page Load, and that includes a PostBack. So you have to move the DataBinding of the Repeater outside the !IsPostBack check.
Protected Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs)
fieldRepeater.DataSource = loadDataHere
fieldRepeater.DataBind
End Sub
Protected Sub Button1_Click(ByVal sender As Object, ByVal e As EventArgs)
Dim i As Integer = 0
For Each item As RepeaterItem In fieldRepeater.Items
Dim temp As DropDownList = CType(item.FindControl(("testField" + i.ToString)),DropDownList)
temp.BackColor = Color.Red
i = (i + 1)
Next
End Sub

Related

asp.net textbox array with events

I have the following code in the page source:
<asp:Button ID="Button1" runat="server" Text="Button" />
And in code behind page:
Protected Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
For i As Integer = 0 To 9
Dim box As New TextBox()
box.ID = "textBox" + CStr(i)
box.Width = 20
box.Text = CStr(i)
box.TabIndex = CShort(i + 1)
AddHandler box.TextChanged, AddressOf ClickBox
panel1.Controls.Add(box)
Next
End Sub
Private Sub ClickBox(sender As Object, e As EventArgs)
Dim boxUsed = DirectCast(sender, TextBox)
boxUsed.BackColor = Drawing.Color.Crimson
End Sub
The problem is TextChange event for texboxes doesn't fire.
Two things. First:
box.AutoPostBack = True
Second:
Since you're creating textboxes dynamically, they will be gone between every postback, unless you re-create them in the Page_Load event.

Writing a passed Array via session into Label isn't working

I am trying to take an array of string (Filled from a listbox on a previous page and passed via Session) and display it in a label,this is how i got the array:
Protected Sub Button1_Click(sender As Object, e As EventArgs) Handles CheckOut.Click
Dim x = ListBox1.GetSelectedIndices.Count
Dim ListPNames(x) As String
Dim i As Integer
i = 0
For Each item As String In ListBox1.GetSelectedIndices
ListPNames(i) = (ListBox1.SelectedItem).ToString
i = i + 1
Next
Session("SlctdPhones") = ListPNames(x)
Response.Redirect("CheckOut.aspx")
End Sub
And this is how i am trying to display it :
Protected Sub Page_Load(sender As Object, e As EventArgs) Handles Me.Load
Dim SlctdPhones() As String = CType(Session.Item("SlctdPhones"), Array)
Dim i As Integer
Label3.Text = ""
For i = 0 To SlctdPhones.Length - 1
Label3.Text += SlctdPhones(i).ToString() + Environment.NewLine
Next
End Sub
It is giving me an error :Object reference not set to an instance of an object. when it reaches the SlctdPhones.Length - 1 Line!!
i don't know how i can fix it ,also is my array code correct(Is everything being stored correctly in it?)
You declare the For loop like this:
For Each item In ...
But then never use the item variable in the body of the loop. Instead, you keep using the same SelectedItem property. You want to change that whole method to look like this:
Protected Sub Button1_Click(sender As Object, e As EventArgs) Handles CheckOut.Click
Dim PNames As New List(Of String)()
For Each index As Integer In ListBox1.GetSelectedIndices
PNames.Add(ListBox1.Items(index).Value)
Next
Session("SlctdPhones") = PNames
Response.Redirect("CheckOut.aspx")
End Sub
With that fixed, the Page_Load can do this:
Protected Sub Page_Load(sender As Object, e As EventArgs) Handles Me.Load
Dim SlctdPhones As List(Of String) = TryCast(Session.Item("SlctdPhones"), List(Of String))
If SlctdPhones Is Nothing OrElse SlctdPhones.Length = 0 Then
'Something went wrong here!
Return
End If
Label3.Text = String.Join("<br/>", SlctdPhones.ToArray())
End Sub
But I'd really love to see you use a data control rather than stuffing <br/>s into a label. Here's markup for a ListView:
<asp:ListView ID="ListView1" runat="server">
<LayoutTemplate>
<ul>
<asp:PlaceHolder ID="itemPlaceholder" runat="server" />
</ul>
</LayoutTemplate>
<ItemTemplate>
<li><%# Container.DataItem.ToString() %></li>
</ItemTemplate>
<EmptyDataTemplate>
<p>Nothing here.</p>
</EmptyDataTemplate>
</asp:ListView>
And then Page_Load is even simpler:
Protected Sub Page_Load(sender As Object, e As EventArgs) Handles Me.Load
ListView1.DataSource = Session.Item("SlctdPhones")
ListView1.DataBind()
End Sub
On display page, use Literal instead of Label
Dim SlctdPhones() As String = CType(Session.Item("SlctdPhones"), Array)
Dim result as String = string.Join("<br>", SlctdPhones) 'Instead of <br> try Environment.NewLine as well
YourLitetal = result
Hope this helps!

How to get current cell value of gridview in asp.net? strautoid retrieves nothing

Protected Sub GridView1_RowUpdating(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewUpdateEventArgs) Handles GridView1.RowUpdating
sqlqrystrng = "UPDATE temp_zone set zone_id = #zoneid, zone_name = #zonename WHERE auto_id = #autoid"
Dim strautoid As String = GridView1.Rows(e.RowIndex).Cells(1).Text
'Dim strautoid As String = Int(GridView1.SelectedRow.Cells(0).Text.ToString())
grid_view_load()
End Sub
sqlqrystrng = "UPDATE temp_zone set zone_id = #zoneid, zone_name = #zonename WHERE auto_id = #autoid"
Dim strautoid As String = GridView1.Rows(e.RowIndex).Cells(e.ColumnIndex).Text
grid_view_load()
Dim Gridview1 As New DataTable
For i As Integer = 0 To Gridview1.Rows.Count - 1
Gridview1.Rows(i).Item(0).ToString()
Next
End Sub
I used a DataTable instead of a gridview because the project I have open is a windows service not a form app but it should work the same
<%# Page Language="VB" %>
<%# Import Namespace="System.Data" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<script runat="server">
Protected Sub Page_Load()
If Not Page.IsPostBack Then
' Create a new table.
Dim taskTable As New DataTable("TaskList")
' Create the columns.
taskTable.Columns.Add("Id", GetType(Integer))
taskTable.Columns.Add("Description", GetType(String))
taskTable.Columns.Add("IsComplete", GetType(Boolean))
'Add data to the new table.
For i = 0 To 19
Dim tableRow = taskTable.NewRow()
tableRow("Id") = i
tableRow("Description") = "Task " + i.ToString()
tableRow("IsComplete") = False
taskTable.Rows.Add(tableRow)
Next
'Persist the table in the Session object.
Session("TaskTable") = taskTable
'Bind data to the GridView control.
BindData()
End If
End Sub
Protected Sub TaskGridView_PageIndexChanging(ByVal sender As Object, ByVal e As GridViewPageEventArgs)
TaskGridView.PageIndex = e.NewPageIndex
'Bind data to the GridView control.
BindData()
End Sub
Protected Sub TaskGridView_RowEditing(ByVal sender As Object, ByVal e As GridViewEditEventArgs)
'Set the edit index.
TaskGridView.EditIndex = e.NewEditIndex
'Bind data to the GridView control.
BindData()
End Sub
Protected Sub TaskGridView_RowCancelingEdit()
'Reset the edit index.
TaskGridView.EditIndex = -1
'Bind data to the GridView control.
BindData()
End Sub
Protected Sub TaskGridView_RowUpdating(ByVal sender As Object, ByVal e As GridViewUpdateEventArgs)
'Retrieve the table from the session object.
Dim dt = CType(Session("TaskTable"), DataTable)
'Update the values.
Dim row = TaskGridView.Rows(e.RowIndex)
dt.Rows(row.DataItemIndex)("Id") = (CType((row.Cells(1).Controls(0)), TextBox)).Text
dt.Rows(row.DataItemIndex)("Description") = (CType((row.Cells(2).Controls(0)), TextBox)).Text
dt.Rows(row.DataItemIndex)("IsComplete") = (CType((row.Cells(3).Controls(0)), CheckBox)).Checked
'Reset the edit index.
TaskGridView.EditIndex = -1
'Bind data to the GridView control.
BindData()
End Sub
Private Sub BindData()
TaskGridView.DataSource = Session("TaskTable")
TaskGridView.DataBind()
End Sub
</script>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>GridView example</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:GridView ID="TaskGridView" runat="server"
AutoGenerateEditButton="True"
AllowPaging="true"
OnRowEditing="TaskGridView_RowEditing"
OnRowCancelingEdit="TaskGridView_RowCancelingEdit"
OnRowUpdating="TaskGridView_RowUpdating"
OnPageIndexChanging="TaskGridView_PageIndexChanging">
</asp:GridView>
</div>
</form>
</body>
</html>

viewState value is not shown after first postback

I'm new to asp.net (after programming for years in classic asp). I'm trying to build a page which adds something to a string.
My code is following:
default.aspx
<body>
<form id="form1" runat="server">
<div>
<p><asp:textbox id="tb" runat="server"></asp:textbox></p>
<asp:Panel ID="tbPanel" runat="server"></asp:Panel>
</div>
</form>
</body>
Code behind:
Partial Class demo_Default
Inherits System.Web.UI.Page
Public Property gesStr As String
Set(value As String)
ViewState("gesStr") = value
End Set
Get
Dim o As Object = ViewState("gesStr")
If o Is Nothing Then
Return ""
Else
Return o
End If
End Get
End Property
Protected Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs) Handles Me.Load
Dim anzeigeStr As String = ""
If Page.IsPostBack Then
Else
gesStr = "1;"
End If
tb.Text = gesStr
Dim iButton As New Button
iButton.Text = "add"
iButton.CommandArgument = "1;"
AddHandler iButton.Click, AddressOf add
tbPanel.Controls.Add(iButton)
Me.anzeige()
End Sub
Private Sub add(ByVal sender As Object, ByVal e As EventArgs)
Dim myButton As Button = DirectCast(sender, Button)
Dim addString As String = myButton.CommandArgument
gesStr += addString
End Sub
Private Sub anzeige()
Dim gesArray As Array = Split(gesStr, ";")
For xLauf As Integer = 0 To UBound(gesArray) - 1
Dim anzLabel As New Label
anzLabel.Text = "<p>" & gesArray(xLauf) & "</p>"
tbPanel.Controls.Add(anzLabel)
Next
End Sub
End Class
The problem:
Pressing the button will cause a postBack, but the result of adding won't appear until the button is pressed a second time. The desired result is that the sub displays the correct array within the loop after the first time pressing the button.
Thank you so much for any help!
You need to call the function anzeige() and bind gesStr value to the textbox control each time the button is click. See the code below:
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If Page.IsPostBack Then
Else
gesStr = "1;"
End If
tb.Text = gesStr
Dim iButton As New Button
iButton.Text = "add"
iButton.CommandArgument = "1;"
iButton.CommandName = "1;"
AddHandler iButton.Click, AddressOf add
tbPanel.Controls.Add(iButton)
End Sub
Private Sub add(ByVal sender As Object, ByVal e As EventArgs)
Dim myButton As Button = DirectCast(sender, Button)
Dim addString As String = myButton.CommandArgument
gesStr += addString
anzeige()
End Sub
Private Sub anzeige()
Dim gesArray As Array = Split(gesStr, ";")
For xLauf As Integer = 0 To UBound(gesArray) - 1
Dim anzLabel As New Label
anzLabel.Text = "<p>" & gesArray(xLauf) & "</p>"
tbPanel.Controls.Add(anzLabel)
Next
'Bind gesStr value to the textbox control
tb.Text = gesStr
End Sub

Page lifecycle is causing an error with user controls within sub

Thanks to #Angkor Wat I achived a major step towards my goal: dynamic adding of pieces of strings to a string. But I came across another thing I cannot solve.
Here is the script:
<%# Page Language="VB" AutoEventWireup="false" CodeFile="addtostring.aspx.vb" Inherits="demo_addtostring" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<div>
<p><asp:textbox id="tb" runat="server"></asp:textbox></p>
<asp:Panel ID="tbPanel" runat="server"></asp:Panel>
</div>
</form>
</body>
</html>
This is the code behind:
Partial Class demo_addtostring
Inherits System.Web.UI.Page
Public Property gesStr As String
Set(value As String)
ViewState("gesStr") = value
End Set
Get
Dim o As Object = ViewState("gesStr")
If o Is Nothing Then
Return ""
Else
Return o
End If
End Get
End Property
Protected Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs) Handles Me.Load
If Page.IsPostBack Then
Else
gesStr = "1;"
End If
tb.Text = gesStr
Dim iButton As New Button
iButton.Text = "add"
iButton.CommandArgument = "1;"
iButton.CommandName = "1;"
AddHandler iButton.Click, AddressOf add
tbPanel.Controls.Add(iButton)
If Page.IsPostBack Then
Else
anzeige()
End If
End Sub
Private Sub add(ByVal sender As Object, ByVal e As EventArgs)
Dim myButton As Button = DirectCast(sender, Button)
Dim addString As String = myButton.CommandArgument
gesStr += addString
tb.Text = gesStr
anzeige()
End Sub
Private Sub anzeige()
Dim gesArray As Array = Split(gesStr, ";")
For xLauf As Integer = 0 To UBound(gesArray) - 1
Dim anzeigeDiv As New System.Web.UI.HtmlControls.HtmlGenericControl("div")
Dim anzLabel As New Label
anzLabel.Text = gesArray(xLauf)
anzeigeDiv.Controls.Add(anzLabel)
Dim iButton2 As New Button
iButton2.Text = xLauf.ToString
iButton2.ID = "test" & xLauf.ToString
iButton2.CommandArgument = "1;"
iButton2.CommandName = "1;"
AddHandler iButton2.Click, AddressOf add
anzeigeDiv.Controls.Add(iButton2)
tbPanel.Controls.Add(anzeigeDiv)
Next
End Sub
End Class
Clicking on the add-button should add "1;" to gesStr - the dynamic loop-generated buttons should do the same -.- Does anyone have an idea? I would be very thankful for help...
In order for the postback to know about the event handler from the button, the button needs to be recreated prior to the point in the lifecycle where the handler is invoked. In other words, you will always need to recreate the buttons within your Page_Load.
Here is a modification to your code which works:
<form id="form1" runat="server">
<div>
<p><asp:textbox id="tb" runat="server"></asp:textbox></p>
<br />
<asp:Button runat="server" ID="btnAdd" Text="add" CommandArgument="1;" />
<asp:Panel ID="tbPanel" runat="server"></asp:Panel>
</div>
</form>
And code-behind:
Public Property gesStr As String
Get
Dim o As Object = ViewState("gesStr")
If o Is Nothing Then
Return ""
Else
Return DirectCast(o, String)
End If
End Get
Set(value As String)
ViewState("gesStr") = value
End Set
End Property
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If Not Page.IsPostBack Then
gesStr = "1;"
End If
tb.Text = gesStr
End Sub
Private Sub add(ByVal sender As Object, ByVal e As CommandEventArgs) Handles btnAdd.Command
Dim addString As String = e.CommandArgument
gesStr += addString
tb.Text = gesStr
CreateNewButton(tbPanel.Controls.Count, addString.Substring(0, addString.Length - 1))
End Sub
Protected Overrides Sub CreateChildControls()
MyBase.CreateChildControls()
Dim gesArray As Array = Split(gesStr, ";")
For xLauf As Integer = 0 To UBound(gesArray) - 1
CreateNewButton(xLauf, gesArray(xLauf))
Next
End Sub
Private Sub CreateNewButton(ByVal xLauf As Integer, ByVal labelText As String)
Dim anzeigeDiv As New Panel
anzeigeDiv.ID = "div" & xLauf.ToString()
Dim anzLabel As New Label
anzLabel.Text = labelText
anzeigeDiv.Controls.Add(anzLabel)
Dim iButton2 As New Button
iButton2.Text = xLauf.ToString
iButton2.ID = "test" & xLauf.ToString()
iButton2.CommandArgument = "1;"
iButton2.CommandName = "1;"
AddHandler iButton2.Command, AddressOf add
anzeigeDiv.Controls.Add(iButton2)
tbPanel.Controls.Add(anzeigeDiv)
End Sub
I've moved the add button, which will always exist, into the aspx page, so that the dynamic panel will only contain the buttons which have been added based on gesStr value.
Dynamic controls must be re-created in every postback see this article for more information.

Resources