Loop through Dynamically Created Controls - asp.net

What I am trying to do is dynamically create a bunch of dropdown lists and then I want to loop through them and update the database with those values, but the problem I am facing is that I create the dropdown lists, but then when I go back to loop through them they are no longer in the panel. I don't know why but when I am debugging I have a count of 50 controls in pnlTeacherSelect right up until I press the button that calls prcChoose.
Called on Page Load
Sub prcSetTeachers()
For Each Subject In ds.Tables("Subject").Rows
Dim Temp As New DropDownList
pnlTeacherSelect.Controls.Add(Temp)
Temp.ID = "drp" & Subject.Item(0) & "s" & Child.Item(0)
Next
End Sub
Called on Clicking a button
Sub prcChoose()
For Each DropDownList In pnlTeacherSelect.Controls.OfType(Of DropDownList)
'This is never executed
Next
End Sub
Any ideas what's causing it? Thanks in advance!

You have to recreate all dynamically created controls on every postback(in load event at the latest).
You also have to ensure that they get the same ID as before to trigger events and maintain ViewState.
If you know the number of controls to create(which could be stored in ViewState) you can derive the ID from the counter variable by appending it to the control-id. Then you can recreate them with the correct ID in page's init event.
Recommandable readings:
TRULY Understanding Dynamic Controls
Page-Lifecycle
Or you use one of the builtin Data-Bound Control like Repeater that do this automatically. You only have to set their DataSource and call DataBind().
Here are answers of me on similar questions with implementations:
C#
VB.NET (+ C#)

Related

ASP NET Dropdown box in a user control losing viewstate

I have a usercontrol in an ASP NET web application on which I create dropdown lists based on some loaded data (from an XML file via a component in the BIN directory)
I found that I couldn't retrieve the values across postbacks, and I've been doing a fair bit of reading to figure out why. What I would like someone to explain is why the following condition exists:
Dim dd As New DropDownList
With dd
.Items.Add(New ListItem("First Item"))
.Items.Add(New ListItem("Second Item"))
.Items.Add(sts(0))
.Items.Add(sts(1))
.Items.Add(sts(2))
.Items.Add(New ListItem("Third Item"))
End With
AddHandler dd.SelectedIndexChanged, AddressOf changed
divControls.Controls.Add(dd)
In the code above the three items 'First Item', 'Second Item' and 'Third Item' all behave correctly, as you can see they are added directly to the dropdown box in code. The items sts(0), sts(1) and sts(2) are all loaded from an XML file into either an array or list of string
Interestingly, sts(0) always posts back correctly, but any subsequent items which are added from the dynamic source don't. I've tried a bunch of ways of getting my list of strings into the dropdown so that they are still there upon postback but I'm not having much luck, would be most grateful if anyone could shed some understanding on this
I figured it out - I need to give each ListItem a value, I had lazily coded just the text portion since I wasn't using ordinals in the list, but ASP NET needed the ordinal value, or the list item value, to register the item for event validation, I expect ASP NET was only able to give subsequent items in the array or list of string the same ordinal or listitem value as all the other members of the collection, since they are from the same object. Works now!

Casting a control to another page

I have tried everything to no avail. I need to cast the value from a user selected dropdownlist to another dropdownlist on another page. The data in the textboxes are a series of numbers.
Also is there a way to display the value in the second dropdown list as well as other values? For example, my dropdown has the values 1-6, user selects 4, which displays first in the dropdown on page 2 but the other values also display in case they want to change there selection??
If Not Page.PreviousPage Is Nothing Then
Dim table As Control = PreviousPage.Controls(0).FindControl("table1")
Dim ddl As DropDownList = CType(table.FindControl("ddlB_Codes"),c DropDownList)
If Not ddl Is Nothing Then
ddl_OC.DataSource = ddl.SelectedValue.Substring(0, 6)
End If
End If
Quick update I FINALLY got my casting to work through a session, only now I need to know how to display the session values and the other additional values for my drop box in case the user wants to change something? Thanks for the help
ddl_OC.DataSource = CType(Session.Item("valCodes"), String)
ddl_OC.DataBind()
ddl_SO.DataSource = CType(Session.Item("valAccts"), String)
ddl_SO.DataBind()
Use event selectedvaluechanged to set datasource for another DropDownList, when first one is changed.
Don't forget to populate it vin DataBind function usage.

Pre-Select Items in a dynamically populated CheckBoxList

I've been experimenting with this and trying to understand the Page Life Cycle for hours upon hours. I'm completely stumped at this point :'( Any help would be GREATLY appreciated.
Below are my methods. My _PrefillWizard method actually works for all the controls on my page except for those which are dynamically populated. The CheckBoxLists are such because they are automatically generated based on selectable values in a table in my DB. I already have this control in my markup like so... how do I force this to load and be ready before running my other code?
<asp:CheckBoxList ID="MyLanguagesCBL" runat="server" RepeatDirection="Vertical"
RepeatColumns="4" Width="100%" DataSourceID="LanguagesSDS"
DataTextField="Language" DataValueField="ID">
</asp:CheckBoxList>
<asp:SqlDataSource ID="LanguagesSDS" runat="server"
ConnectionString="<%$ ConnectionStrings:ConnectionString1 %>"
SelectCommand="select ID, [Language] from LanguagesListTable"
DataSourceMode="DataReader">
</asp:SqlDataSource>
Obviously these particular controls are not yet generated or on the page by the time my _PrefillWizard has been called, resulting in none of the CheckBoxes being pre-filled. How do I make them generate before my prefill method is called? Thanks ;)
The click event that kicks things off.
'On "Load" Button click, clears a Wizard control and Prefills it with the
' data from the clicked record based on the primary key stored in SessionState.
Protected Sub RowClick(ByVal sender As Object, ByVal e As GridViewCommandEventArgs) Handles GridView2.RowCommand
If e.CommandName = "Select" Then
Session.Add("ClickedPrimaryKey", GridView2.DataKeys(e.CommandArgument).Value.ToString)
'This is the main function which calls "_SetCheckBoxes" among others.
_PrefillWizard(Session.Item("ClickedPrimaryKey"))
End If
End Sub
Here's my function for populating the my CheckBoxList control, but it obviously depends on the control having already been loaded on the page.
'Parse a CSV String from the Database back into CheckBoxList Selections
Protected Sub _SetCheckBoxes(ByRef cbl As CheckBoxList, ByRef dt As DataTable, ByVal row As Integer, ByVal csv As String)
'Do something if there is a value in the cell
If Not IsDBNull(dt.Rows.Find(row)(csv)) Then
For Each item As ListItem In cbl.Items
item.Selected = False 'Reset the checkbox first
'Then, if the ID value of the checkbox corresponds to a value
' in the CSV string, then tick the checkbox.
If csv.Contains(item.Value) Then
item.Selected = True
End If
Next
End If
End Sub
Here is a potential idea, and one that we have used before in a similar situation:
Because the Page Init event is fired before the click handler, you can actually examine Request.Form("__EventTarget") and, if it is your row click, add the new CheckBoxList to the appropriate container (page, tab, etc).
If you are adding multiple controls, you will have to be sure that you track the added items somewhere in the page so that they can be automatically re-created each time Page Init is fired.
You guys will probably get a kick out of this, but the answer was so obvious that I didn't even catch it all this time. Of course I was preoccupied with about 10 other functions too >.<
Here's the answer. You'll notice that in my _SetCheckBoxes method, I first checked to ensure that a value existed for the particular csv string, but also notice, that I failed to actually SET it to the corresponding value string afterward. This isn't immediately apparent, but what I was actually passing in as csv was the name of the Column in my DataTable where the string actually lived.
csv = dt.Rows.Find(row)(csv).ToString
That line added immediately after my IsDBNull check, fixed my problem. :)

Iteratively Reference Controls by Name Pattern (VB.NET)

Is there a way to iteratively reference an ASP.NET control based on it's name pattern? Perhaps by a "pointer" or something?
What I have are a large set of comboboxes (each with an associated DropDownList and TextBox control). The DropDownList always has an item selected by default, but the use may wish to submit a NULL value. I come up with the following code to handle three cases: NULL, Existing Item, New Item.
'TextBoxControl & DropDownListControl should iteratively reference their
' respective TextBox & DropDownList controls by the actual control name
If StrComp(TextBoxControl.Text, DropDownListControl.SelectedItem.ToString) = 0 Then
'When an Existing Item is selected, Do Something
ElseIf Not TextBoxControl.Text = "" Then
'When a New Item is entered, Validate & Do Something
Else
'When NULL, Do Something
End If
The problem is, with so many comboboxes, I could easily end up with hundreds of lines of code. I wish to handle this in a more dynamic way, but I do not know if it is possible to reference controls in this way. Say I wanted to reference all the TextBox Controls and DropDownList Controls, respectively.
I can do string formatting with a given naming pattern to generate a name ID for any of the controls because they are all named with the same pattern. For example by attaching a specific suffix, say "_tb" for TextBox Controls and "_ddl" for DropDownList Controls:
Left(item.SelectedItem.ToString, item.SelectedItem.ToString.Length - 3) + "_tb"
Can this sort of thing be done in VB? Ultimately, my goal is to take the value entered/selected by the user, if any, and send it to a stored procedure on SQL Server for insertion into the database.
Yes. Write your code inside of a function having parameters for the textbox and the dropdown, and then write the function in terms of those two parameters. Then you simply call that function for every set instead of copy/pasting code everywhere.
Don't attempt choosing things by name. That's fragile and imposes machine requirements on a field that'd designed for human consumption.
I am not sure if the samething that applies VBA will apply to your situation, but I had the same issue and was able to use:
Me.MultiPage1.Pages(1).Controls("ref" & i + 1).Value
where controls encompasses all controls on the userform ("Me"). So if the controls in your program conform to a consecutive naming structure it is easy handle if the above applies vb.net

Insert record with EmptyDataTemplate in asp:ListView

I have an EmptyDataTemplate in my asp:ListView which I want to use to insert a new record.
I have Inserting working in the InsertItemTemplate... I thought I could copy the InsertItemTemplate into the EmptyDataTemplate, on clicking Insert this gives the error
Insert can only be called on an insert item. Ensure only the InsertTemplate has a button with CommandName=Insert.
How can I use the EmptyDataTemplate to Insert a row? Do I need to use the OnClick of the button to access the values within the EmptyDataTemplate and do an Insert by myself?
I'm using LinqDataSource
You might have figured it by now
but if you set the InsertItemPosition to anything other than None the EmptyData Template will not be rendered i.e it will always show the insert template
you can read more here
http://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.listview.emptydatatemplate.aspx
No way if want to insert data in empty data template.
It is possible to do an insert from the EmptyDataTemplate by handcrafting the insert. I am using a listview to display a static number of rows based on a unique filtered item. I am basically listing all the static attributes of an object. In the case where a new object is filtered on that does not have any attributes associated with it, i use the EmptyDataTemplate of the listview to display a HTMLTable that contains asp.net controls to capture data. I have a command button within the table that i evaluate using the ListView_ItemCommand. If the CommandName matches that of the "Insert" button within the EmptyDataItem, I use the ListView.Controls(0).FindControl method to locate my table. I then loop through my table and do inserts on the data found within each row. I included the how to find a control within the htmltable. In my code I am actually grabbing a bunch of controls then crafting the sql and using a SQLConnection to perform the insert.
Protected Sub ListView_ItemCommand(sender As Object, e As System.Web.UI.WebControls.ListViewCommandEventArgs) Handles ListView.ItemCommand
Select Case e.CommandName
Case "Submit"
Dim edt As HtmlTable = ListView.Controls(0).FindControl("myhtmltable")
Dim ddl As DropDownList = CType(edt.FindControl("mydropdownlist"), DropDownList)
'Perform Insert
Case "Some other commandname"
End Select
End Sub
You will need to still do error checking and databind() and refresh your listview.
Is this the best way. Maybe not... But it is possible.
~Ian

Resources