Home > OS >  Is there a way to use variables to control the ID of html tags for a code-behind page in VB.NET?
Is there a way to use variables to control the ID of html tags for a code-behind page in VB.NET?

Time:07-12

I'm making a simple form. I have Default.aspx, Default.aspx.vb, and Default.aspx.designer.vb.
Default.aspx.vb contains a Public jsonItems As List(Of JsonItem), where a JsonItem is just an object with a few strings defined, like Id, Label, and Type. This is generated by Page_Load, which reads a Json file to tell the page the form's contents.

Then, Default.aspx contains:

    <ul>
      <%For Each item In jsonItems%>
      <li>
        ...
        <ol>
          <asp:TextBox ID="<%=item.Label%>" runat="server"></asp:TextBox>
        </ol>
      </li>
      <%Next%>
    </ul>

This, however, doesn't work as I would expect it to. I believe this is because the Designer page wants to know exactly what form elements will be on the page... It autogenerates Protected WithEvents <%=item.label%> As ... in the designer page, and complains that it isn't a valid name.

Is there a way to do what I'm trying to do? Should I be building the entire form in the.. code-behind (Default.aspx.vb) instead of what I'm doing now?

For the record, I'm used to working in React, which is why I initially took this direction (I wrote it first in JS and I was adapting it to VB).

CodePudding user response:

Injection of asp.net controls into a page does not tend to work very well at all.

You can inject HTML, but then again , you now writing your own code anyway, and again that not a huge help.

As a general approach?

Should I be building the entire form in the.. code-behind

No, you don't want to write that much code. You lay out the markup with the designer - code behind is to pull data say to fill out those existing controls.

I mean, you have to define that markup some place. But with web forms, the general idea is that you drop in the controls you want.

Of course, there is a boat load of controls, and many are data aware. So, the trick, the idea, the goal?

Well, with so many control choices, it often hard to pick a control.

So, for a table like layout, then GridView. For fancy table layout, then ListView.

For repeating records - say like a "card view", then datalist works well.

so in webforms land? You tend to layout the markup with the desinger.

Then you use code behind to fill out the data, or whatever.

So, say I drop in a Gridview, like this:

    <asp:GridView ID="GHotels" runat="server" AutoGenerateColumns="False" 
            DataKeyNames="ID" CssClass="table">
            <Columns>
                <asp:BoundField DataField="FirstName" HeaderText="FirstName"  />
                <asp:BoundField DataField="LastName" HeaderText="LastName"    />
                <asp:BoundField DataField="HotelName" HeaderText="HotelName"  />
                <asp:TemplateField>
                    <ItemTemplate>
                        <asp:CheckBox ID="chkActive" runat="server" Checked='<%# Eval("Active") %>' />
                    </ItemTemplate>
                </asp:TemplateField>
                <asp:TemplateField HeaderText="Hotel Information" ItemStyle-HorizontalAlign="Center">
                    <ItemTemplate>
                        <asp:Button ID="cmdView" runat="server" Text="Info" CssClass="btn" 
                            OnClick="cmdView_Click" />
                    </ItemTemplate>
                </asp:TemplateField>
            </Columns>
        </asp:GridView>

I did use the wizard to help me create the GV. (but then I removed the sql datasource that was created on the page).

So, now my code to say load up the grid would be this:

Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
    If Not IsPostBack Then
        LoadGrid
    End If
End Sub

Sub LoadGrid()

    Dim rstData As DataTable
    rstData = MyRst("SELECT * FROM tblHotelsA ORDER BY HotelName")
    GHotels.DataSource = rstData
    GHotels.DataBind()

End Sub

Public Function MyRst(strSQL As String) As DataTable
    Dim rstData As New DataTable
    Using conn As New SqlConnection(My.Settings.TEST4)
        Using cmdSQL As New SqlCommand(strSQL, conn)
            conn.Open()
            rstData.Load(cmdSQL.ExecuteReader)
            rstData.TableName = strSQL
        End Using
    End Using
    Return rstData
End Function

And I get this:

enter image description here

Note how I did set the GV to CssClass="table". (that is the boot strap class - so you get a nice looking gird).

And I have a button - edit that row.

Again, just a plain jane button click for that row.

So, right below the Grid, I could drop in a div, and some controls to display/edit that one row.

Say, like this:

    <div id="HotelInfo" runat="server" 
        style="float:left;display: none;border:solid;padding:15px;background-color:white;width:48%"
        clientidmode="Static" >
        <style>
            .iForm label {display:inline-block;width:120px}
            .iForm input {border-radius:8px;border-width:1px;margin-bottom:10px}                
            .iForm textarea {border-radius:8px;border-width:1px;margin-bottom:10px}     
            .iForm input[type=checkbox] {margin-right:4px}
        </style>

        <div style="float:left" >
                <label>HotelName</label><asp:TextBox ID="txtHotel" runat="server"  width="280"></asp:TextBox> <br />
                <label>First Name</label><asp:TextBox ID="txtFirst" runat="server"  width="280"></asp:TextBox> <br />
                <label>Last Name</label><asp:TextBox ID="txtLast" runat="server"  width="280"></asp:TextBox> <br />

                <label>City</label><asp:TextBox ID="tCity" runat="server"  Width="140"></asp:TextBox> <br />
                <label>Province</label><asp:TextBox ID="tProvince" runat="server"  Width="75"></asp:TextBox> <br />
        </div>
        <div style="float:left;margin-left:20px" >
            <label>Description</label> <br />
            <asp:TextBox ID="txtNotes" runat="server" Width="450" TextMode="MultiLine" 
                Height="150px"  ></asp:TextBox> <br />
            <asp:CheckBox ID="chkActive" Text=" Active" runat="server" TextAlign="Right" />
            <asp:CheckBox ID="chkBalcony"  Text=" Has Balcony" runat="server" TextAlign="Right" />
            <asp:CheckBox ID="chkSmoking" Text="Smoking Rooms" runat="server" TextAlign="Right" />
        </div>

        <div style="clear:both">
            <asp:Button ID="cmdSave" runat="server" Text="Save" CssClass="btn" />
            <asp:Button ID="cmdCancel" runat="server" Text="Cancel" CssClass="btn"
                style="margin-left:20px" OnClientClick="$('#HotelInfo').dialog('close');return false;"
                />
            <asp:Button ID="cmdDelete" runat="server" Text="Delete" CssClass="btn"
                style="margin-left:40px"
                />
        </div>
    </div>

And, since we all ahve jquery instaleld, I added jquery.UI.

So right after above, I have this:

    <script>
        function popinfo(pbtn, strHotelName) {

            // btn = row buttion - we use that for position of pop
            btn = $(pbtn)
            myDialog = $("#HotelInfo")
            myDialog.dialog({
                title: strHotelName,
                modal: true,
                position: { my: "left top", at: "right bottom", of: btn },
                width: "48%",
                appendTo: 'form'
            })
        }
    </script>

So, now our row click event:

Protected Sub cmdView_Click(sender As Object, e As EventArgs)

    ' Row click - get hotel informaton, fill out the pop div
    Dim btn As Button = sender
    Dim gRow As GridViewRow = btn.NamingContainer

    Dim intPK As Integer = GHotels.DataKeys(gRow.RowIndex).Item("ID")
    Dim rstData As DataTable = MyRst("SELECT * FROM tblHotelsA WHERE ID = " & intPK)


    Call EditOne(rstData, btn)


End Sub

Sub EditOne(rstData As DataTable, btn As Button)

    With rstData.Rows(0)
        txtHotel.Text = .Item("HotelName").ToString
        txtFirst.Text = .Item("FirstName").ToString
        txtLast.Text = .Item("LastName").ToString
        tCity.Text = .Item("City").ToString
        tProvince.Text = .Item("Province").ToString
        chkActive.Checked = .Item("Active")
        chkBalcony.Checked = .Item("Balcony")
        chkSmoking.Checked = .Item("Smoking")
        txtNotes.Text = .Item("Description").ToString
    End With

    ' ok, div information filled out, now call our js pop function.
    Dim strHotelName = """Edit Information for " & rstData.Rows(0).Item("HotelName") & """"
    Dim strJavaScript As String = "popinfo(" & btn.ClientID & "," & strHotelName & ");"

    ViewState("rstData") = rstData
    Page.ClientScript.RegisterStartupScript(Me.GetType(), "My Pop script", strJavaScript, True)


End Sub

So, now we see/get this when we click on a row button:

enter image description here

the save button in above, say this code:

Protected Sub cmdSave_Click(sender As Object, e As EventArgs) Handles cmdSave.Click

    Dim rstData As DataTable = ViewState("rstData")

    With rstData.Rows(0)
        .Item("HotelName") = txtHotel.Text
        .Item("FirstName") = txtFirst.Text
        .Item("LastName") = txtLast.Text
        .Item("City") = tCity.Text
        .Item("Province") = tProvince.Text
        .Item("Active") = chkActive.Checked
        .Item("Balcony") = chkBalcony.Checked
        .Item("Smoking") = chkSmoking.Checked
        .Item("Description") = txtNotes.Text
    End With

    Using conn As New SqlConnection(My.Settings.TEST4)
        Using cmdSQL As New SqlCommand("SELECT * FROM tblHotelsA", conn)
            conn.Open()
            Dim da As New SqlDataAdapter(cmdSQL)
            Dim daU As New SqlCommandBuilder(da)
            da.Update(rstData)
        End Using
    End Using

    LoadGrid()

End Sub

So, the above should give you some ideas here.

I actually became tired of wirting the same code to send a row of data to controls on a page, so I wrote a simple routine to do that for me. Same goes for saving the data back to the table.

so, with a few helper routines, then you quite much just drag drop to add controls to a page - and then a few helper routines.

So, my load code, and save code to load up controls? that is now a general routine and I thus don't even hand code that anymore.

I adopted a extra attribuote that I add to controls.

So, my markup becomes say this:

<div style="float:left" >
 <label>HotelName</label>
 <asp:TextBox ID="txtHotel" runat="server"  width="280" f="HotelName" ></asp:TextBox> <br />
 <label>First Name</label>
 <asp:TextBox ID="txtFirst" runat="server" width="280" f="FirstName" ></asp:TextBox> <br />
    <label>Last Name</label>
    <asp:TextBox ID="txtLast" runat="server"  width="280" f="LastName"></asp:TextBox> <br />

So, in palce of those multiple lines of code to load up the controls, I now can do this:

This:

Sub EditOne(rstData As DataTable, btn As Button)

    With rstData.Rows(0)
        txtHotel.Text = .Item("HotelName").ToString
        txtFirst.Text = .Item("FirstName").ToString
        txtLast.Text = .Item("LastName").ToString
        tCity.Text = .Item("City").ToString
        tProvince.Text = .Item("Province").ToString
        chkActive.Checked = .Item("Active")
        chkBalcony.Checked = .Item("Balcony")
        chkSmoking.Checked = .Item("Smoking")
        txtNotes.Text = .Item("Description").ToString
    End With

    ' ok, div information filled out, now call our js pop function.
    Dim strHotelName = """Edit Information for " & rstData.Rows(0).Item("HotelName") & """"

becomes:

    Call fLoader(HotelInfo, rstData.Rows(0))

So, now, it one line of code to load 5 or 25 controls with the data.

I can post that routine.

But, all in all?

You don't really write code to create the markup. But, code behind supports the data operations of what you want to do against the controls.

So, some kind of on-the fly generation of markup? Web forms not the best choice for that kind of design approach - it just not.

so, it rather difficult to generate controls and a id, but worse as you note, you have even more difficult time adding events to such controls.

  • Related