so I have this code for grid view in asp.net
<asp:GridView ID="grdNewClaim" CssClass="table table-bordered table-condensed" GridLines="None" runat="server" AutoGenerateColumns="false">
<Columns>
<asp:BoundField DataField="claim_type" HeaderText="Claim Type" />
<asp:BoundField DataField="purpose_desc" HeaderText="Purpos/Description" />
<asp:BoundField DataField="currency" HeaderText="Currency" />
<asp:BoundField DataField="amount" HeaderText="Amount" />
<asp:TemplateField HeaderText="Currency Rate">
<ItemTemplate>
<asp:TextBox ID="txtChangeCurrRate" runat="server"></asp:TextBox>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Converted Rate">
<ItemTemplate>
<asp:TextBox ID="txtChangeConvertedRate" runat="server"></asp:TextBox>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
And this code to add the new row for the gridview
Private Sub addClaimProgrammatically()
Dim dt As New DataTable
Dim dr As DataRow
If grdNewClaim.Rows.Count = 0 Then
dt.Columns.Add("claim_type")
dt.Columns.Add("purpose_desc")
dt.Columns.Add("currency")
dt.Columns.Add("amount")
dt.Columns.Add("txtChangeCurrRate")
dt.Columns.Add("txtChangeConvertedRate")
dr = dt.NewRow
dr.Item("claim_type") = cmbClaimtype.Text
dr.Item("purpose_desc") = txtPurpDesc.Text
dr.Item("currency") = cmbCurrency.Value
dr.Item("amount") = txtAmmount.Text
dr.Item("txtChangeCurrRate") = lblCurrencyrate.Text
dr.Item("txtChangeConvertedRate") = lblconvertedRateMYR.Text
dt.Rows.Add(dr)
End If
grdNewClaim.DataSource = dt
grdNewClaim.DataBind()
End Sub
But for some reason the items for for both textbox just blank like this :
So any idea why? Because if I change the textbox to <asp:BoundField/>
it works just fine like this
CodePudding user response:
When you use a boundfield, it works because you CAN SPECIFY which column to display.
bound field only works due to this:
Computers do not "guess" or "assume" what data column to use here.
But, when you use a templated column, and a standard control, then you need to use a expression that defines which column to use.
eg this:
<asp:TemplateField HeaderText="Currency Rate">
<ItemTemplate>
<asp:TextBox ID="txtChangeCurrRate" runat="server"></asp:TextBox>
</ItemTemplate>
</asp:TemplateField>
so, in above, ask this question: Where in above does the markup KNOW which column to use?
So, you have to use a binding expression, since TextBox does not have a "boundfield" property to tell it which column to use.
Try like this:
<asp:TemplateField HeaderText="Currency Rate">
<ItemTemplate>
<asp:TextBox ID="txtChangeCurrRate" runat="server"
Text = '<%# Eval("Currency") %>'
></asp:TextBox>
</ItemTemplate>
</asp:TemplateField>
So, in above, we would be using column "Currency" for the text (or you can use "amount" or "purpose_desc" or any column from the data source.
So, your example does not work, since with a templated textbox, you have to specify the column to use - (by some how and some way). So, use the above binding expression.
Edit: data does not persist - only can add one row.
Correct - you need to save that table between each post-back, and NOT re-create the table from scratch each time, else you lose previous rows.
So, the code has to look like this:
NOTE how I defined dt at the class level (right before page load).
And note how I "restore" this dt in page load EACH time.
So, your code will become this
Markup like this:
<asp:GridView ID="grdNewClaim" CssClass="table table-bordered table-condensed"
GridLines="None" runat="server" AutoGenerateColumns="false"
ShowHeaderWhenEmpty="true" >
<Columns>
<asp:BoundField DataField="claim_type" HeaderText="Claim Type" />
<asp:BoundField DataField="purpose_desc" HeaderText="Purpos/Description" />
<asp:BoundField DataField="currency" HeaderText="Currency" />
<asp:BoundField DataField="amount" HeaderText="Amount" />
<asp:TemplateField HeaderText="Currency Rate">
<ItemTemplate>
<asp:TextBox ID="txtCRateZoo" runat="server"
Text = '<%# Eval("txtChangeCurrRate") %>'>
</asp:TextBox>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Converted Rate">
<ItemTemplate>
<asp:TextBox ID="txtConvertedRate" runat="server"
Text = '<%# Eval("txtChangeCurrRate") %>' >
</asp:TextBox>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
And code now like this:
Dim dt As New DataTable
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If Not IsPostBack Then
CreateTable()
LoadGrid()
Session("dt") = dt
Else
' restore table
dt = Session("dt")
End If
End Sub
Sub CreateTable()
dt.Columns.Add("claim_type", GetType(String))
dt.Columns.Add("purpose_desc")
dt.Columns.Add("currency", GetType(Double))
dt.Columns.Add("amount", GetType(Double))
dt.Columns.Add("txtChangeCurrRate", GetType(Double))
dt.Columns.Add("txtChangeConvertedRate", GetType(Double))
End Sub
Sub LoadGrid()
grdNewClaim.DataSource = dt
grdNewClaim.DataBind()
End Sub
Private Sub addClaimProgrammatically()
Dim dr As DataRow
dr = dt.NewRow
dr.Item("claim_type") = cmbClaimtype.Text
dr.Item("purpose_desc") = txtPurpDesc.Text
dr.Item("currency") = cmbCurrency.Value
dr.Item("amount") = txtAmmount.Text
dr.Item("txtChangeCurrRate") = lblCurrencyrate.Text
dr.Item("txtChangeConvertedRate") = lblconvertedRateMYR.Text
dt.Rows.Add(dr)
LoadGrid()
End Sub
Edit2: allow edits of two text box - save back to table.
So, just add this to the code:
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If Not IsPostBack Then
CreateTable()
LoadGrid()
Session("dt") = dt
Else
' restore table
dt = Session("dt")
' restore grid to dt
GridToTable
End If
End Sub
Sub GridToTable()
' move any and all possile updates to grid back to our table dt
For Each gRow As GridViewRow In grdNewClaim.Rows
Dim OneRow As DataRow = dt.Rows(gRow.RowIndex)
Dim txtCurrRate As TextBox = gRow.FindControl("txtCRateZoo")
Dim txtConvertRate As TextBox = gRow.FindControl("txtConvertedRate")
OneRow("txtChangeCurrRate") = txtCurrRate.Text
OneRow("txtChangeConvertedRate") = txtConvertRate.Text
Next
End Sub
What we do is send any changes back to the dt.
This means, that any button click etc on that page will shuffle gv back to dt.
This also means that if you have a button click to jump or move on to the next page/url, then session("dt") will have the correct data.
but, since we doing this on page load, then don't use a link button, or a button with post-back url to jump to the next page (just use regular button code behind, and say:
Response.Redirect("url to next page to jump to")
So, with above, user can now freely modify the two columns, and they will be sent back to the dt.
This also means you can loop/process the dt in code.
Say we drop a button on the form, and then behind that button we do this:
Protected Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
For Each OneRow As DataRow In dt.Rows
Debug.Print(OneRow("currency"))
Debug.Print(OneRow("txtChangeCurrRate"))
' etc . etc.
Next
End Sub
So, we don't even have to hit the original grid, and it will be always updated in our session(). As such, then we could have a button "continue" to move on to the next page - as along as we follow above setup, then dt will always have the latest data and edits upon a post-back.