I’ve managed to successfully create a panel with dynamically created label and textbox created controls and now I need to be able to place them in a 1 (easy), 2 or 3 column display within the panel (based on user selection). This is the code that generates the controls"
If MydataSet.Tables(0).Rows.Count > 0 Then
For Each MyDataRow As DataRow In MydataSet.Tables(0).Rows
Me.CreateLabel("lblDynamic_" & MyDataRow("ID"), MyDataRow("Title"))
Me.CreateTextBox("txtDynamic_" & MyDataRow("ID"))
Next
End If
CreateLabel and CreateTextbox code:
Private Sub CreateTextBox(id As String)
Dim txt As New TextBox()
txt.ID = id
Panel_AdditionalData.Controls.Add(txt)
Dim lt As New Literal()
lt.Text = "<br />"
Panel_AdditionalData.Controls.Add(lt)
End Sub
Private Sub CreateLabel(id As String, value As String)
Dim lbl As New Label()
lbl.ID = id
lbl.Text = value
lbl.CssClass = "label"
Panel_AdditionalData.Controls.Add(lbl)
Dim lt As New Literal()
lt.Text = "<br />"
Panel_AdditionalData.Controls.Add(lt)
End Sub
Obviously there is more code to manage postbacks and retrieving inputted data, but for the purposes of layout posting that code isn’t relevant.
I retrieve the user defined data fields from the database and use that information to create each control. Creating each control in a single column is easy, just add the control, no problem. I’ve already done that. However, creating a multi-column layout is proving to be difficult and everything I’ve tried thus far has failed. Anyone have any suggestions?
2
Answers
As my research and the comments/answers posted in response to my question point out, there are a myriad of ways one can get the job done. Given my time constraints and the need to get the infrastructure in place to provide this functionality to my users, I went with the "quick and relatively" easy method.
This is what I went with:
The page that contains the dynamic controls will not be posted back to the server via the usual post back method but rather by an ajax method and json data posted to a web method in the code behind to avoid any issues with maintaining the dynamic fields on a post back. I have been gradually going to this method of posting back data as it is (apparently) very efficient and avoids screen refreshing and I am able to provide immediate feedback to the user in real time a lot more cleanly. I find that very appealing. In this particular instance it also solves the problem of linking the data to a particular entity whether it is a new or existing (edited) entity.
One of the approaches in webforms is always try to achieve this with a data bound option. (GridView, ListView, Repeater). Not only does this simplify the code, but MORE important when it comes time to click on a row, process a row etc., then you have a lot more "row click" options. And even in those cases in which you don’t need a row click option, you still are better off to use some layout for repeating data.
While you can "claim" that the controls are "dynamic" in your approach, looking at the code, we see hard coded column names anyway.
So, I not saying you never should "write code" to inject controls to repeat data and place controls on the web form, but I am suggesting you ONLY want to go down that road after exhausting the data bound choices we have.
In other words, while quite a few web approaches do "hint" and "suggest" that you can inject controls, in web form land, it should be a last resort.
I have done boatloads of work in web forms, and in fact I can’t EVER think of a case in which using the built in system to "repeat" data (and thus controls) was always the better choice. As noted, the result then in effect a type of "object" on the form that your code behind can now process with great ease.
I’ll also point out that injected controls tend to NOT keep their view state, and thus any post back means such controls are NOT persisted, and thus on every post back, such controls will disappear, and that injecting code will have to run again. All in all, it gets real messy real fast. So, exhaust the easy road and choices first.
My personal favorite is the ListView. (it has unlimited layout, can render as a grid, but like Access continues forms, you can have more then one line for the controls that make up one record of the data source).
While a GridView also works well, I find when using standard controls (that I want to fill out and repeat for each row a bit of a pain, since each control has to be placed inside of a template start tag and end tag. So, for just a few columns, then GridView is fine, but for more complex layout (and more columns) then jumping over to the ListView wins the day.
So, most simple would be a repeater. It will repeat the markup for each data row.
So, I might then say have this:
(FirstName, LastName, HotelName).
So, then this:
So, while it takes somewhat more markup, our code behind now becomes very simple, since all we do is "feed" the data.
Hence this code:
And the result is this:
And our button click can now with ease process some rows.
Say this code:
So, it doesn’t matter if we have 2 or 15 rows. Our code is still the same.
The result thus looks like this:
However, as noted, much better would be to use a "column" layout, and thus a GridView, or ListView would be a better choice.
But, the bonus and cool part? I can change what my markup looks like, but VERY little code behind now changes (a huge bonus here).
So, let’s use a GridView.
Note how I applied the bootstrap class "table, and table-hover. This makes the GridView "size" automatic to whatever page size you have (it’s responsive). And note the nice hover effect.
This:
And my code behind is almost the same. The nice advantage (of GridView or ListView) is they allow you to "hide" and not have to show the database PK id in the markup (this is nice for added security).
So, code behind is now this:
In the first data load, I have this:
And the row processing code is this:
And say for some rows, I did not want the Hotel to show, there are many options I can have/choose to hide and format each row – and I don’t have to write loops for above.
And I can do things like highlight the given row, say based on some other column in the database.
But, again, note how my code did not change much, and this demonstrates how placing your layout things in the markup and NOT code behind allows layouts to be changed with ease.
Almost no code changes occurred for a vast different layout.
So, this post is already a bit long, but it does show that using some kind of "data aware" control moves out the layout code and controls code to the markup. Thus, code behind becomes less efforts.
Where the "huge" gains come is if you need to then accept, see, or view the controls, and if the user makes changes to not only the check box, but the text box controls, then you again can loop over that set of controls, and once again, the code to save/send such data back to the database can be done with far greater ease.
I am most tempted to post a ListView, since as noted, I tend to like that control the most, and this is especially the case if the data in the controls has to be changed, or saved back to the database.
Also, for completeness, I fast become tired of typing code over and over to pull data, so I have some helper routines (global module), and used my handy dandy MyRst routine.
That code was this:
Now, if your goal is to SAVE the typed in data for above? (or allow edits), then just ask, and I’ll post some code to deal with that (and I do NOT suggest using the built in edit events and editing, since they are a messy pain to use).