Creating a Table/DataList/DataGrid with dynamic controls and variable number of columns

Hello,

after posting another questions which seems to be difficult to answer(http://www.experts-exchange.com/Programming/Languages/.NET/ASP.NET/Q_24326178.html), i just want to ask for a different approach to the problem. My goal is the following:

1. Create a table (datalist or whatever control you suggest) that holds a variable number of columns. The column names are retrieved using a database query. There are three static columns that are always there: "Name" should be the second column in the table, "Active" the last. The column retrieved with the query should be in between those two. Name holds a label, Active an Image. Each row holds a button(edit button) in the first column (to the left of the "Name" column).

2. The columns retrieved from the database hold a label in each row to display text.

3. If the edit button is clicked, the "Name" columns label is turned into a Textbox, the Image for Active into a Checkbox. The labels in the dynamically added columns turn into Textboxes. The first column now holds a save and cancel imagebutton.

4. On cancel the row goes back to normal display state with labels and image.

5. On save the values entered by the user are saved to the database


My question is now how do i achieve this? The way im currently doing it (see my other question) does not work as i loose the state of the dynamically created Textboxes during postbacks. Please lay out some code which does exactly this. You dont need to provide the database code or code for cancel as i have that already. Im only interested how and especially in which methods to create the dynamic controls and how to make sure to keep their state once the save button is clicked. (The tricky part seems to be where to create the dynamic controls in order to have their viewState managed)

Thank you!
_b3nAsked:
Who is Participating?
 
wht1986Commented:
In that case I might do something like define the active image column on the page itself, so i could use the template column. then when i did the insert of boundfield i would place it before the active column instead of at the end.  Something like the following

The rest of the code stays the same.
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False" onrowediting="GridView1_RowEditing">
    <Columns>
        <asp:CommandField ShowEditButton="True" />
        <asp:BoundField DataField="Column1" HeaderText="Name" />
        <asp:TemplateField HeaderText="Active">
            <ItemTemplate>
                <asp:Image ID="img1" ImageUrl="Active.gif" runat="server" Visible="<%# Eval("IsActive") %>" />
                <asp:Image ID="img2" ImageUrl="NotActive.gif" runat="server" Visible="<%# !Eval("IsActive") %>" />
            </ItemTemplate>
            <EditItemTemplate>
                <asp:CheckBox ID="cb1" runat="server" Checked='<%# Bind("IsActive") %>' />
            </EditItemTemplate>
        </asp:TemplateField>
    </Columns>
</asp:GridView>
 
    private void SetColumns()
    {
        DataSet1TableAdapters.TestTableTableAdapter adpt = new DataSet1TableAdapters.TestTableTableAdapter();
        DataSet1.TestTableDataTable tbl = adpt.GetData();
        foreach (DataColumn col in tbl.Columns)
        {
            BoundField fld = new BoundField();
            fld.DataField = col.ColumnName;
            fld.HeaderText = col.ColumnName;
            this.GridView1.Columns.Insert(this.GridView1.Columns.Count-2, fld);
        }
    }

Open in new window

0
 
wht1986Commented:
Just a first pass at this before i head to bed.  Why not create the first to columns statically and create the rest dynamically, below is a quick sample. you need to add the other cancel events etc
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="false" 
    onrowediting="GridView1_RowEditing">
    <Columns>
        <asp:CommandField ShowEditButton="True" />
        <asp:BoundField DataField="Column1" HeaderText="Name" />
    </Columns>
</asp:GridView>
 
protected void Page_Load(object sender, EventArgs e)
{
    if (!this.IsPostBack)
    {
        RefreshGrid();
    }
}
 
protected void Button1_Click(object sender, EventArgs e)
{
    // empty dataset
    DataSet1 ds = new DataSet1();
 
    // create an adapter
    DataSet1TableAdapters.TestTableTableAdapter adpt = new DataSet1TableAdapters.TestTableTableAdapter();
 
    // get the records
    adpt.Fill(ds.TestTable);
 
    // add a new record
    ds.TestTable.AddTestTableRow(this.TextBox1.Text, this.TextBox2.Text);
 
    adpt.UpdateWithTransaction(ds.TestTable);
 
    RefreshGrid();
}
 
private void RefreshGrid()
{
    DataSet1TableAdapters.TestTableTableAdapter adpt = new DataSet1TableAdapters.TestTableTableAdapter();
    this.GridView1.DataSource = adpt.GetData();
    this.GridView1.DataBind();
}

Open in new window

0
 
_b3nAuthor Commented:
How does this help me in generating a dynamic number of controls and maintaining their state? Have a look at my linked post, i added some pictures to it so you can actually see what the whole thing should look like.

thanks!
0
Free Tool: Path Explorer

An intuitive utility to help find the CSS path to UI elements on a webpage. These paths are used frequently in a variety of front-end development and QA automation tasks.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

 
wht1986Commented:
Sorry cut and paste error (im very sleepy), this code is what i meant to post. It will auto generate the columns and handle the edit command.  sorry about pasting the wrong file clip in before.
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="false" 
    onrowediting="GridView1_RowEditing">
    <Columns>
        <asp:CommandField ShowEditButton="True" />
        <asp:BoundField DataField="Column1" HeaderText="Name" />
    </Columns>
</asp:GridView>
 
public partial class Default2 : System.Web.UI.Page
{
    private void SetColumns()
    {
        DataSet1TableAdapters.TestTableTableAdapter adpt = new DataSet1TableAdapters.TestTableTableAdapter();
        DataSet1.TestTableDataTable tbl = adpt.GetData();
        foreach (DataColumn col in tbl.Columns)
        {
            BoundField fld = new BoundField();
            fld.DataField = col.ColumnName;
            fld.HeaderText = col.ColumnName;
            this.GridView1.Columns.Add(fld);
        }
 
        ImageField fld1 = new ImageField();
        fld1.HeaderText = "Active";
        this.GridView1.Columns.Add(fld1);
    }
 
    private void SetData()
    {
        DataSet1TableAdapters.TestTableTableAdapter adpt = new DataSet1TableAdapters.TestTableTableAdapter();
        DataSet1.TestTableDataTable tbl = adpt.GetData();
        this.GridView1.DataSource = tbl;
        this.GridView1.DataKeyNames = new string[] { "PrimaryID" };
        this.GridView1.DataBind();
 
    }
 
    protected void Page_Load(object sender, EventArgs e)
    {
        if (!this.IsPostBack)
        {
            SetColumns();
            SetData();
        }
    }
 
    protected void GridView1_RowEditing(object sender, GridViewEditEventArgs e)
    {
        this.GridView1.EditIndex = e.NewEditIndex;
        SetData();
    }
}

Open in new window

0
 
wht1986Commented:
Its not a turn key solution but it gives the beginning framework to do what you want
Capture.JPG
Capture1.JPG
0
 
wht1986Commented:
finally if you want the textboxes as multiline you can add this code to the edit event
    protected void GridView1_RowEditing(object sender, GridViewEditEventArgs e)
    {
        this.GridView1.EditIndex = e.NewEditIndex;
        SetData();
 
        for (int i = 2; i < this.GridView1.Columns.Count - 1; i++)
        {
            TableCell c = this.GridView1.Rows[this.GridView1.EditIndex].Cells[i];
            TextBox t = (TextBox)c.Controls[0];
            t.TextMode = TextBoxMode.MultiLine;
        }
    }

Open in new window

0
 
_b3nAuthor Commented:
First of all thanks for your effort. I was looking through your code, but i couldnt find the place where it creates the TextBoxes. Where exactly is that done?
0
 
wht1986Commented:
The textboxes are created on the fly by the GridView. Basically im adding to the grid bound columns through the BoundField.  by default bound fields are rendered as labels during view mode and as textboxes when editing.  Im letting the GridView do all the work on maintaing controls and state.  Im looping through the columns of some dataset data table, and adding a bound field for each column.
0
 
_b3nAuthor Commented:
Thanks for the explanation! It sounds like a good start. However, there is one questions left. The active column displays a picutre in my table. If i want to display a checkbox in editmode, how would i let the gridview know that it should display a picture in normal mode and a checkbox in editmode?
0
 
_b3nAuthor Commented:
Thanks for that, ill give it a try and let you know how its going!
0
 
_b3nAuthor Commented:
So here is my current status:

I created a gridview and added my columns to it. Since the gridview uses linkbuttons for edit, update and cancel i tried to use imagebuttons. I created an imagebutton in the itemtemplate for edit, and two imagebuttons in the edittemplate for cancel and update. The problem is that whenever i click on the edit button, the rowedit event is not fired. If i move the button out of the template as a buttonfield it fires. Also, when the gridview goes to editmode, it doesnt show the checkbox and the two buttons in the edittemplate. My code looks like this, what am i doing wrong?


<asp:GridView ID="gvAssessableElement" runat="server" HeaderStyle-CssClass="DLHeaderTable" HeaderStyle-Height="22px" AutoGenerateColumns="false" GridLines="none" CellPadding ="1" CellSpacing="0" Width="100%">
	<AlternatingRowStyle CssClass="DLAlternatingItemStyle" />
	<Columns>
		<asp:ButtonField ButtonType ="Image" ImageUrl="./content/images/imgEdit.png" CommandName="edit" />
		<asp:TemplateField HeaderText="Active" HeaderStyle-HorizontalAlign="Center" ItemStyle-HorizontalAlign="center" >
			<ItemTemplate >
				<asp:ImageButton id="btnEdit" runat="server" ImageUrl="./content/images/imgEdit.png" CommandName="edit"/>                                                                                         
				<asp:Image ID="imgActive" ImageUrl ="./content/images/imgActive.png" runat="server" Visible='<%# Eval("Active") %>'/>
				<asp:Image ID="imgInactive" ImageUrl ="./content/images/imgInactive.png" runat="server" Visible='<%# Not Eval("Active") %>'/>
			</ItemTemplate>
			<EditItemTemplate>
				<asp:ImageButton ID="btnSave" runat="server" ImageUrl="./content/images/imgSave.png" CommandName="update"/>                                                                                         
				<asp:ImageButton ID="btnCancel" runat="server" ImageUrl="./content/images/imgCancel.png" CommandName="cancel"/>                                                                                         
				<asp:CheckBox ID="chbActive" runat="server" />
			</EditItemTemplate>
		</asp:TemplateField> 
	</Columns>
</asp:GridView>
 
    Private Sub createColumns()
        Dim mode As String = CStr(Session(PAGEMODE_ASSESSABLEELEMENT & PageHeader1.PageUniqueNumber))
        Dim standardlist As ArrayList = Standard.getStandards(ddlAssessableElementYear.SelectedYear.Year, False)
        Dim width As Integer = 0
        If standardlist.Count > 0 Then
            width = 75 / standardlist.Count
        End If
 
        If gvAssessableElement.Columns.Count < 3 Then
 
            gvAssessableElement.HeaderStyle.CssClass = "DLHeaderTable"
 
            Dim boundField As BoundField = New BoundField
            boundField.DataField = "Name"
            boundField.HeaderText = "Name"
            boundField.HeaderStyle.CssClass = "DLColumnHeader"
            boundField.HeaderStyle.HorizontalAlign = HorizontalAlign.Left
            boundField.ItemStyle.Width = System.Web.UI.WebControls.Unit.Percentage(15)
            gvAssessableElement.Columns.Insert(1, boundField)
 
            For Each standard As Standard In standardlist
                boundField = New BoundField
                boundField.HeaderStyle.CssClass = "DLColumnHeader"
                boundField.HeaderStyle.HorizontalAlign = HorizontalAlign.Left
                boundField.DataField = standard.Name
                boundField.HeaderText = standard.Name
                boundField.ItemStyle.Width = System.Web.UI.WebControls.Unit.Percentage(width)
                gvAssessableElement.Columns.Insert(gvAssessableElement.Columns.Count - 1, boundField)
            Next
        End If
        bindData()
    End Sub
 
    Private Sub bindData()
        Session(PAGEMODE_ASSESSABLEELEMENT & PageHeader1.PageUniqueNumber) = ""
 
        Dim selectionCriteria As ArrayList = New ArrayList
        If ddlAssessableElementKLA.SelectedIndex <> -1 Then
            selectionCriteria.Add(ddlAssessableElementKLA.SelectedKLA)
        End If
        'If ddlAssessableElementYear.SelectedIndex <> -1 Then
        '    selectionCriteria.Add(ddlAssessableElementYear.SelectedYear)
        'End If
 
        If selectionCriteria.Count = 0 Then
            hiddenError.Value = "You must select at least one KLA, Strand and Level Juncture to search by."
        End If
 
        If Not SecurityManager.isCurriculumEditor Then
            selectionCriteria.Add(True)
        End If
 
        Dim dataSet As New DataSet
        Dim assessableElementList As ArrayList = AssessableElement.getObjects(False, selectionCriteria)
        Dim standardList As ArrayList = Standard.getStandards(ddlAssessableElementYear.SelectedYear.Year, False)
 
        Dim dataTable As DataTable = dataSet.Tables.Add(TABLE_ASSESSABLEELEMENT)
        dataTable.Columns.Add(COLUMN_ASSESSABLEELEMENT, GetType(AssessableElement))
        dataTable.Columns.Add(COLUMN_ORDER, GetType(Integer))
        dataTable.Columns.Add(COLUMN_NAME, GetType(String))
        dataTable.Columns.Add(COLUMN_ACTIVE, GetType(Boolean))
 
        For Each standard As Standard In standardList
            dataTable.Columns.Add(standard.Name, GetType(String))
        Next
 
        For Each assessableElement As AssessableElement In assessableElementList
            Dim params As ArrayList = New ArrayList
            params.Add(assessableElement)
            params.Add(assessableElement.Order)
            params.Add(assessableElement.Name)
            params.Add(assessableElement.Active)
            For Each standard As Standard In standardList
                params.Add(assessableElement.QualityDescriptor(standard.StandardId))
            Next
            dataTable.Rows.Add(params.ToArray)
        Next
 
 
        If dataTable.Rows.Count = 0 Then
            divNRFAssessableElements.Visible = True
        Else
            divNRFAssessableElements.Visible = False
        End If
 
        Dim dataView As New DataView(dataTable, "", COLUMN_ORDER, DataViewRowState.CurrentRows)
 
        gvAssessableElement.DataSource = dataView
        gvAssessableElement.DataBind()
 
        If Session(DV_ASSESSABLEELEMENT & PageHeader1.PageUniqueNumber) IsNot Nothing Then
            CType(Session(DV_ASSESSABLEELEMENT & PageHeader1.PageUniqueNumber), DataView).Dispose()
        End If
        Session(DV_ASSESSABLEELEMENT & PageHeader1.PageUniqueNumber) = dataView
 
        If Session(DS_ASSESSABLEELEMENT & PageHeader1.PageUniqueNumber) IsNot Nothing Then
            CType(Session(DS_ASSESSABLEELEMENT & PageHeader1.PageUniqueNumber), DataSet).Dispose()
        End If
        Session(DS_ASSESSABLEELEMENT & PageHeader1.PageUniqueNumber) = dataSet
 
        pnlAssessableElement.Update()
 
    End Sub
 
    Protected Sub gvAssessableElement_RowEditing(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewEditEventArgs) Handles gvAssessableElement.RowEditing
 
        gvAssessableElement.EditIndex = e.NewEditIndex
        bindData()
 
        For i As Integer = 1 To gvAssessableElement.Columns.Count - 2
            Dim cell As TableCell = gvAssessableElement.Rows(gvAssessableElement.EditIndex).Cells(i)
            Dim textBox As TextBox = cell.Controls(0)
            textBox.TextMode = TextBoxMode.MultiLine
            textBox.Rows = 3
        Next
 
 
    End Sub
 
    Private Sub btnAssessableElementSearch_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnAssessableElementSearch.Click
        createColumns()
        gvAssessableElement.Visible = True
        pnlAssessableElement.Update()
    End Sub

Open in new window

0
 
wht1986Commented:
I get the same error.  I see on several other boards that others have this problem with dynamically adding columns to a grid where the template column holds the grid commands. No one seems to have found a resolution for it either.

Below is an old school way to build the table and put it into a placeholder.  Obviously you will have to tweak it, but it does create a dynamic table, and because we set the ID of all the dynamic controls, they hold their values between postabcks.
public partial class Default2 : System.Web.UI.Page
{
    private int EditIndex
    {
        get { return (int)ViewState["EditIndex"]; }
        set { ViewState["EditIndex"] = value; }
    }
 
    protected void Page_Load(object sender, EventArgs e)
    {
        if (!this.IsPostBack)
        {
            EditIndex = -1;
        }
 
        BuildTable();
    }
 
    private void BuildTable()
    {
        // get the data
        DataSet1TableAdapters.TestTableTableAdapter adpt = new DataSet1TableAdapters.TestTableTableAdapter();
        DataSet1.TestTableDataTable data = new DataSet1.TestTableDataTable();
        adpt.Fill(data);
 
        System.Web.UI.HtmlControls.HtmlTable tbl = null;
        System.Web.UI.HtmlControls.HtmlTableRow tr = null;
        System.Web.UI.HtmlControls.HtmlTableCell td = null;
 
        // make the table
        tbl = new System.Web.UI.HtmlControls.HtmlTable();
        tbl.CellPadding = 3;
        tbl.CellSpacing = 0;
 
        // make the header row
        tr = new System.Web.UI.HtmlControls.HtmlTableRow();
        tr.BgColor = "#000";
        tr.Style.Add("color", "#FFF");
        tbl.Rows.Add(tr);
 
        // for command column
        td = new System.Web.UI.HtmlControls.HtmlTableCell();
        tr.Cells.Add(td);
        td.InnerHtml = "&nbsp;";
        
        // for other columns
        foreach (DataColumn column in data.Columns)
        {
            td = new System.Web.UI.HtmlControls.HtmlTableCell();
            tr.Cells.Add(td);
            td.InnerHtml = column.ColumnName;
        }
 
        LinkButton lb = null;
 
        // loop through data
        for (int i = 0; i < data.Rows.Count; i++)
        {
            tr = new System.Web.UI.HtmlControls.HtmlTableRow();
            tbl.Rows.Add(tr);
 
            td = new System.Web.UI.HtmlControls.HtmlTableCell();
            tr.Cells.Add(td);
 
            if (EditIndex == i)
            {
                lb = new LinkButton();
                lb.Style.Add("margin-right", "3px");
                lb.ID = string.Format("LBUPDATE_{0}", i);
                lb.Text = "Update";
                lb.CommandName = "Update";
                lb.CommandArgument = i.ToString();
                td.Controls.Add(lb);
                lb.Click += new EventHandler(lb_Click);
 
                lb = new LinkButton();
                lb.ID = string.Format("LBCANCEL_{0}", i);
                lb.Text = "Cancel";
                lb.CommandName = "Cancel";
                lb.CommandArgument = i.ToString();
                td.Controls.Add(lb);
                lb.Click += new EventHandler(lb_Click);
            }
            else
            {
                lb = new LinkButton();
                lb.ID = string.Format("LBEDIT_{0}", i);
                lb.Text = "Edit";
                lb.CommandName = "Edit";
                lb.CommandArgument = i.ToString();
                td.Controls.Add(lb);
                lb.Click += new EventHandler(lb_Click);
            }
 
            for (int j = 0; j < data.Columns.Count; j++)
            {
                td = new System.Web.UI.HtmlControls.HtmlTableCell();
                tr.Cells.Add(td);
 
                if (EditIndex == i)
                {
                    TextBox tb = new TextBox();
                    tb.ID = string.Format("TB_{0}_{1}", i, j);
                    td.Controls.Add(tb);
                }
                else
                    td.InnerHtml = data[i][j].ToString();
            }
        }
 
        this.PlaceHolder1.Controls.Clear();
        this.PlaceHolder1.Controls.Add(tbl);
 
    }
 
    void lb_Click(object sender, EventArgs e)
    {
        LinkButton lb = (LinkButton)sender;
        switch (lb.CommandName)
        {
            case "Edit":
                EditIndex = int.Parse(lb.CommandArgument);
                break;
            case "Update":
                EditIndex = -1;
                break;
            case "Cancel":
                EditIndex = -1;
                break;
        }
        BuildTable();
    }
}

Open in new window

0
 
_b3nAuthor Commented:
If i created all buttons outside the template with visibility false for the editbuttons, is there a way to set the visibility to true depending on the edit item index?
0
 
wht1986Commented:
I'm not sure, you'll just have to try it out.  I dont know if you have a budget or not, but at my work we use the controls from telerik. I can successfully add columns with it.  They have an example here

http://www.telerik.com/community/forums/aspnet-ajax/grid/dynamically-add-columns-to-existing-radgrid.aspx

You can download a free trial ofthem.

I was bored at little kids b-day party this morning so i wrote some more of the old fashioned code like i showed before. I added the update routines and some minor error handling.

I really suggest trying out the telerik controls, they are pretty awesome and Im sure you can do what you want with them.

public partial class Default2 : System.Web.UI.Page
{
    private void CreateCachedDataSource()
    {
        DataSet1.EmployeesDataTable dataTable = new DataSet1.EmployeesDataTable();
        dataTable.AddEmployeesRow("bvilla", "Bob", "Villa", "111-222-3333", "000-00-1111", DateTime.Now, true);
        dataTable.AddEmployeesRow("ceastwood", "Clint", "Eastwood", "565-222-3333", "123-00-1111", DateTime.Now, false);
        dataTable.AddEmployeesRow("cnorris", "Chuck", "Norris", "111-333-3333", "007-232-2222", DateTime.Now, true);
        dataTable.AcceptChanges();
        SaveDataTable(dataTable);
    }
 
    private DataTable FetchDataTable()
    {
        return (DataTable)ViewState["CachedData"];
    }
 
    private void SaveDataTable(DataTable dataTable)
    {
        ViewState["CachedData"] = dataTable;
    }
 
    private int EditIndex
    {
        get { return (int)ViewState["EditIndex"]; }
        set { ViewState["EditIndex"] = value; }
    }
 
    protected void Page_Load(object sender, EventArgs e)
    {
        if (!this.IsPostBack)
        {
            CreateCachedDataSource();
            EditIndex = -1;
        }
 
        BuildTable();
    }
 
    private void BuildTable()
    {
        this.BuildTable(false);
    }
 
    private void BuildTable(bool applyValues)
    {
        // get the data
        DataTable data = FetchDataTable();
 
        System.Web.UI.HtmlControls.HtmlTable tbl = null;
        System.Web.UI.HtmlControls.HtmlTableRow tr = null;
        System.Web.UI.HtmlControls.HtmlTableCell td = null;
 
        // make the table
        tbl = new System.Web.UI.HtmlControls.HtmlTable();
        tbl.CellPadding = 3;
        tbl.CellSpacing = 0;
 
        // make the header row
        tr = new System.Web.UI.HtmlControls.HtmlTableRow();
        tr.BgColor = "#000";
        tr.Style.Add("color", "#FFF");
        tbl.Rows.Add(tr);
 
        // for command column
        td = new System.Web.UI.HtmlControls.HtmlTableCell();
        tr.Cells.Add(td);
        td.InnerHtml = "&nbsp;";
        
        // for other columns
        foreach (DataColumn column in data.Columns)
        {
            td = new System.Web.UI.HtmlControls.HtmlTableCell();
            tr.Cells.Add(td);
            td.InnerHtml = column.ColumnName;
        }
 
        LinkButton lb = null;
 
        // loop through data
        for (int i = 0; i < data.Rows.Count; i++)
        {
            tr = new System.Web.UI.HtmlControls.HtmlTableRow();
            tbl.Rows.Add(tr);
 
            td = new System.Web.UI.HtmlControls.HtmlTableCell();
            tr.Cells.Add(td);
 
            if (EditIndex == i)
            {
                lb = new LinkButton();
                lb.Style.Add("margin-right", "3px");
                lb.ID = string.Format("LBUPDATE_{0}", i);
                lb.Text = "Update";
                lb.CommandName = "Update";
                lb.CommandArgument = i.ToString();
                td.Controls.Add(lb);
                lb.Click += new EventHandler(lb_Click);
 
                lb = new LinkButton();
                lb.ID = string.Format("LBCANCEL_{0}", i);
                lb.Text = "Cancel";
                lb.CommandName = "Cancel";
                lb.CommandArgument = i.ToString();
                td.Controls.Add(lb);
                lb.Click += new EventHandler(lb_Click);
            }
            else
            {
                lb = new LinkButton();
                lb.ID = string.Format("LBEDIT_{0}", i);
                lb.Text = "Edit";
                lb.CommandName = "Edit";
                lb.CommandArgument = i.ToString();
                td.Controls.Add(lb);
                lb.Click += new EventHandler(lb_Click);
            }
 
            for (int j = 0; j < data.Columns.Count; j++)
            {
 
                td = new System.Web.UI.HtmlControls.HtmlTableCell();
                tr.Cells.Add(td);
 
                if ((EditIndex == i) && (!data.Columns[j].ReadOnly))
                {
                    if (data.Columns[j].ColumnName == "Active")
                    {
                        CheckBox cb = new CheckBox();
                        cb.ID = string.Format("CB_{0}_{1}", i, j);
                        td.Controls.Add(cb);
 
                        if (applyValues)
                            cb.Checked = (bool)data.Rows[i][j];
 
                    }
                    else
                    {
                        TextBox tb = new TextBox();
                        tb.ID = string.Format("TB_{0}_{1}", i, j);
                        td.Controls.Add(tb);
 
                        if (applyValues)
                            tb.Text = data.Rows[i][j].ToString();
                    }
                }
                else
                {
                    if (data.Columns[j].ColumnName == "Active")
                    {
                        System.Web.UI.HtmlControls.HtmlImage img = new System.Web.UI.HtmlControls.HtmlImage();
                        img.Src = ((bool)data.Rows[i][j]) ? "img_active.gif" : "img_inactive.gif";
                        img.Alt = ((bool)data.Rows[i][j]) ? "Active" : "Inactive";
                        td.Controls.Add(img);
                    }
                    else
                        td.InnerHtml = data.Rows[i][j].ToString();
                }
            }
        }
 
        this.PlaceHolder1.Controls.Clear();
        this.PlaceHolder1.Controls.Add(tbl);
 
    }
 
    void lb_Click(object sender, EventArgs e)
    {
        LinkButton lb = (LinkButton)sender;
        switch (lb.CommandName)
        {
            case "Edit":
                EditIndex = int.Parse(lb.CommandArgument);
                BuildTable(true);
                break;
            case "Cancel":
                EditIndex = -1;
                BuildTable();
                break;
            case "Update":
                if (DoTheUpdate())
                {
                    EditIndex = -1;
                    BuildTable();
                }
                break;
        }
    }
 
    private bool DoTheUpdate()
    {
        DataTable dataTable = FetchDataTable();
        
        DataRow editRow = dataTable.Rows[EditIndex];
 
        WebControl ctrl = null;
        try
        {
            for (int j = 0; j < dataTable.Columns.Count; j++)
            {
                // skip readonly
                if (dataTable.Columns[j].ReadOnly)
                    continue;
 
                if (dataTable.Columns[j].ColumnName == "Active")
                {
                    CheckBox cb = (CheckBox)Page.FindControl(string.Format("CB_{0}_{1}", EditIndex, j));
                    ctrl = cb;
                    editRow[j] = cb.Checked;
                }
                else
                {
                    TextBox tb = (TextBox)Page.FindControl(string.Format("TB_{0}_{1}", EditIndex, j));
                    ctrl = tb;
                    string value = tb.Text;
                    if (value == "")
                        editRow[j] = DBNull.Value;
                    else
                        editRow[j] = value;
                }
 
                ctrl.BackColor = System.Drawing.Color.White;
                ctrl.ToolTip = "";
            }
            editRow.AcceptChanges();
            return true;
        }
        catch (Exception exc)
        {
            ctrl.BackColor = System.Drawing.Color.Red;
            ctrl.ToolTip = exc.Message;
            editRow.RejectChanges();
            return false;
        }
    }
 
}

Open in new window

0
 
_b3nAuthor Commented:
Thanks for all the code, but for now i followed a simpler approach than creating the whole table myself. I created three commandfields for edit, cancel and update and in rowBound i check whether it is the row being currently edited and depening on that i shift around the buttons in the cell (if its edit, cause then the edit button is set to invisible) or i hide the cancel and update buttons. It works quite well so far and the buttons also seem to fire the events for the gridview. However, the problem with the checkbox remains, i have to add it manually if there is an edit event. I havent implemented the methods for update and cancel yet, so i dont know if i actually get access to the updated values. I really hope i do otherwise Im not sure what to do from here. Thanks for pointing out the third party control, but unfortunately this is not an option. I will let you know tomorrow about my progress with implementing update and cancel.
0
 
_b3nAuthor Commented:
Ok after implementing the update method i have the problem that i cannot access the checkbox and its value. But since the textboxes are working fine, i give you the points for all your help. I will open another thread about the itemteplate/edittemplate problem tho.

Thanks again for your effort!
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.