2
\$\begingroup\$

I need to add a list of names and (optional) links to my ASP.net page.

I learnt (hopefully) to use a GridView to do this, mostly working from the example given by this blog entry: adding-dynamic-rows-in-gridview.

I've added a GridView to my frontend:

<asp:GridView
        id="NameLinksGridView" runat="server"
        AutoGenerateColumns="false" ShowFooter="true">
    <Columns>
        <asp:TemplateField HeaderText="Name">
            <ItemTemplate>
                <asp:TextBox ID="Name" runat="server" />
            </ItemTemplate>
        </asp:TemplateField> 
        <asp:TemplateField HeaderText="Link">
            <ItemTemplate>
                <asp:TextBox ID="Link" runat="server" />
            </ItemTemplate>
            <FooterStyle HorizontalAlign="Right" />
            <FooterTemplate>
                <asp:Button 
                    ID="addNameLink" runat="server"
                    Text="Add" onclick="addNameLink_Click"
                    CausesValidation="false" />
            </FooterTemplate> 
        </asp:TemplateField>
    </Columns>
</asp:GridView>

With the code behind:

private void setupInitialNameLinks()
{
    DataTable dt = getNameLinksTable();
    /* store DataTable in the ViewState for preservation across PostBack's */
    ViewState["CurrentTable"] = dt;
    /* bind the displayed DataGrid to our DataTable */
    NameLinksGridView.DataSource = dt;
    NameLinksGridView.DataBind();
    /* set current TextBox values to the values in the DataTable 
        * surely the DataBind should do this for us?!? */
    setTextBoxValuesToDataTableValues(dt);
}

private DataTable getNameLinksTable()
{
    DataTable dt = new DataTable();
    dt.Columns.Add(new DataColumn("Name", typeof(string)));
    dt.Columns.Add(new DataColumn("Link", typeof(string)));

    var existingNameLinks = getExistingNameLinks();
    if (existingNameLinks.Count() > 0)
    {
        foreach (var auth in existing)
        {
            DataRow r = dt.NewRow();
            r["Name"] = auth.name;
            r["Link"] = auth.link;
            dt.Rows.Add(r);
        }
    }
    else
    {
        DataRow emptyRow = getNameLinksEmptyRow(dt);
        dt.Rows.Add(emptyRow);
    }
    return dt;
}

private static DataRow getNameLinksEmptyRow(DataTable dt)
{
    DataRow emptyRow = dt.NewRow();
    emptyRow["Name"] = String.Empty;
    emptyRow["Link"] = String.Empty;
    return emptyRow;
}

protected void addNameLink_Click(object sender, EventArgs e)
{
    if (ViewState["CurrentTable"] != null)
    {
        DataTable dt = (DataTable) ViewState["CurrentTable"];
        DataRow dr = getNameLinksEmptyRow(dt);
        dt.Rows.Add(dr);

        /* update our DataTable to the POST'ed data */
        int numPostedRows = dt.Rows.Count - 1;
        for (int i = 0; i < numPostedRows; i++)
        {
            TextBox tbName = 
                (TextBox)NameLinksGridView.Rows[i].Cells[0].FindControl("Name");
            string name = tbName.Text; // get POST'ed value
            dt.Rows[i]["Name"] = name; // set DataTable val to the POST'ed value
            TextBox tbLink = 
                (TextBox)NameLinksGridView.Rows[i].Cells[1].FindControl("Link");
            string link = tbLink.Text;
            dt.Rows[i]["Link"] = link;
        }

        /* store our DataTable in the ViewState for preservation across PostBack */
        ViewState["CurrentTable"] = dt;

        /* bind the displayed DataGrid to our DataTable */
        NameLinksGridView.DataSource = dt;
        NameLinksGridView.DataBind();

        /* set current TextBox values to the values in the DataTable
            * needs to happen after the DataBind()
            * surely the DataBind should do this for us?!? */
        setTextBoxValuesToDataTableValues(dt);

    }
    else
    {
        throw new Exception("CurrentTable is null!");
    }
}

private void setTextBoxValuesToDataTableValues(DataTable dt)
{
    for (int i = 0; i < dt.Rows.Count; i++)
    {
        TextBox tbName = (TextBox)NameLinksGridView.Rows[i].Cells[0].FindControl("Name");
        tbName.Text = dt.Rows[i]["Name"].ToString();
        TextBox tbLink = (TextBox)NameLinksGridView.Rows[i].Cells[1].FindControl("Link");
        tbLink.Text = dt.Rows[i]["Link"].ToString();
    }
}

Does any of this code look troublesome, prone to error, umnaintanable, not the right way of doing it, etc?

One big bit of confusion I have (even though the code works) — why do I need to store the DataTable in the ViewState manually and set my TextBox displayed values manually (in setTextBoxValuesToDataTableValues)? Surely the GridView state should be maintained across the POST without me needing to worry about the ViewState and the DataBind should set the TextBox values automatically?

\$\endgroup\$
1
  • \$\begingroup\$ The KetticGridView is capable of populating gridview with data using DataTable to a single data table or dataset, as well as to multiple data tables through hierarchical data binding. \$\endgroup\$
    – user36445
    Feb 8 '14 at 9:38
2
\$\begingroup\$

Regarding having to get/set the value of the textboxes, you should get to know the Bind expression. For instance, you could have:

<asp:TextBox ID="Name" runat="server" Text='<%# Bind("Name") %>' /> 

For one of the "right" ways of doing things, have a look at this walkthrough of bulk editing rows in the GridView control.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.