ARTICLE

Embedded Datagrids with Add, Edit and Delete funtionality

Posted by Rammanohar Articles | Internet & Web June 02, 2006
This article features an embedded Datagrids with Add, Edit and Delete funtionality.
Reader Level:

The database for this page is

Project_Group_Type (Master Table)
columns (Basic ones):  

Project_Group_Type_ID Description
1 New

Project_Group (Details Table)
columns(Basic ones) :   

Project_Group_ID Project_Group_Type_ID Project_Group_Description
1 1 Check

The DataSource

The data source for the Master Datagrid consists of these columns: Project_Group_Type_ID, Description

The data source for the Details Datagrid consists of these columns: Project_Group_ID Project_Group_Type_ID Project_Group_Description

The Datagrid is within another Datagrid (Figure 1).The master Datagrid has project categories Type  and details Datagrid have projects Categories. The detail table has a foreign to the master table.

 



Figure 1

The details Datagrid is expanded as shown in Figure 2.

Figure 2

Now the user can add/edit/delete row to the master/details Datagrid. Now I have created this as user control and used in other aspx pages.

The code is as follows. Declare the Datagrid with following attributes.

<asp:DataGrid ID="dgProjectGroupType" ShowFooter="True" ShowHeader="false" AutoGenerateColumns="False"

CellSpacing="0" BorderStyle="None" BorderWidth="0" GridLines="None" CellPadding="0" Width="100%" runat="server"            OnItemDataBound="dgProjectGroupType_ItemDataBound" OnItemCommand="dgProjectGroupType_ItemCommand">

I have enabled show footer = true in order to add new record for this grid. I have added a new row with textbox and add button. And since I donot require the header have set it to false. I have following events for

  • ItemDataBound: To bind the Inner grid with outer grid.
  • ItemCommand: Handling the events on the master like add,edit,cancel...etc

<FooterStyle Font-Size="Smaller"  />

<ItemStyle Font-Size="Smaller" />

<EditItemStyle BackColor="#CADDEE" Font-Size="Smaller" />

<SelectedItemStyle BackColor="#D1DDF1" Font-Bold="True"       ForeColor="#333333" Font-Size="Smaller" />

<PagerStyle BackColor="#2461BF" ForeColor="White" HorizontalAlign="Center" Font-Size="Smaller" />

<HeaderStyle Font-Size="Smaller" />

<AlternatingItemStyle Font-Size="Smaller" />

This is style format I have used for grid, which self explanatory.

<Columns>

The "Columns" is declared under "<Columns>" tags since AutoGenerateColumns is "False".

 

<asp:TemplateColumn HeaderText="" >

<FooterTemplate>

           <asp:TextBox ID="addDescription" runat="Server" />

      </FooterTemplate>

      <ItemTemplate>

&nbsp;&nbsp;&nbsp; <b> <%#DataBinder.Eval(Container.DataItem,"Description")%>

</b>

      </ItemTemplate>

      <EditItemTemplate>

          <asp:TextBox ID="storDescription"

Text=

'<%# DataBinder.Eval(Container.DataItem,"Description")%>'

            runat="server" />

       </EditItemTemplate>

</asp:TemplateColumn>

The footer template, editItem template, item template  for this column are declared under "asp:TemplateColumn".

<asp:TemplateColumn HeaderText="">

<ItemTemplate>

<asp:Label ID="projectGroupTypeID" runat="server" Text=

'<%# DataBinder.Eval(Container.DataItem, "Project_Group_Type_Id")%>' Visible="False" />

      </ItemTemplate>

</asp:TemplateColumn>

This column is used for the editing the master records. This column is the primary key for this master table. Hence made invisible and retrived by the ID of lable and used in internal operations.

<asp:TemplateColumn HeaderText="">

<ItemTemplate>

<asp:DataGrid ID="dgProjectGroup" ShowFooter="True" ShowHeader="true" AutoGenerateColumns="False"

BorderWidth="0" GridLines="None" CellPadding="0" Width="100%" runat="server" OnItemCommand="dgProjectGroup_ItemCommand"

            OnItemDataBound="dgProjectGroup_OnItemDataBound">

 

                   <FooterStyle Font-Size="Smaller" />

            <ItemStyle Font-Size="Smaller" />

            <EditItemStyle BackColor="#CADDEE" Font-Size="Smaller" />

<SelectedItemStyle BackColor="#D1DDF1" Font-Bold="True" ForeColor="#333333" Font-Size="Smaller" />

<PagerStyle BackColor="#2461BF" ForeColor="White" HorizontalAlign="Center" Font-Size="Smaller" />

<HeaderStyle Font-Size="Smaller" />

<AlternatingItemStyle Font-Size="Smaller" />

Here in the "asp:TemplateColumn" where columns are decalred, another datagrid is declared. I have following events for

  • ItemDataBound : refer See code in css.
  • ItemCommand  : Handling the events on the details grid like add, edit, cancel...etc

This is style format I have used for grid, which self explainatary.

<Columns>

The "Columns" is declared under "<Columns>" tags since AutoGenerateColumns is "False".

                   <asp:TemplateColumn HeaderText="">

                             <ItemTemplate>

<asp:Label ID="projectGroupDescription" runat="server" Text='<%# DataBinder.Eval(Container.DataItem, "Project_Group_Description")%>'

                  Width="275px" />

                    </ItemTemplate>

            <EditItemTemplate>

<asp:TextBox ID="txtGroup" Text='<%# DataBinder.Eval(Container.DataItem, "Project_Group_Description") %>'

                  runat="server" Width="275px" />

                </EditItemTemplate>

      <FooterTemplate>

<asp:TextBox ID="addProject" runat="Server" Text="" />

<asp:TextBox ID="addProjectTypeID" runat="Server" Text="" Visible="False" />

            </FooterTemplate>

</asp:TemplateColumn>

Then in the detials datagrid ,Iam displaying the project group description in an itemTemplate,displaying in textbox in edit mode and displaying a empty text on footer of the datagrid.

<asp:TemplateColumn>

          <ItemTemplate>

<asp:Button ID="cmdEditprojectGroup" runat="server" Text="Edit" CommandName="EditGroup" />

<asp:Button ID="cmdDeleteprojectGroup" runat="server" Text="Delete" CommandName="DeleteGroup" />

            </ItemTemplate>

            <EditItemTemplate>

<asp:Button ID="cmdUpdateMeasure" runat="server" Text="Save" CommandName="SaveGroup" />

<asp:Button ID="cmdCancelEditprojectGroup" runat="server" Text="Cancel" CommandName="CancelGroup" />

            </EditItemTemplate>

<FooterStyle    VerticalAlign="Middle"></FooterStyle>

            <FooterTemplate>

<asp:Button ID="cmdAddMeasure" CommandName="InsertGroup" runat="server" Text="Add" />

            </FooterTemplate>

</asp:TemplateColumn>

Again in the details datagrid ,Iam displaying the Edit & delete buttons in an itemTemplate,displaying in save & cancel buttons in edit mode and displaying a add button on footer of the datagrid.

<asp:TemplateColumn HeaderText="" Visible="False">

                   <ItemTemplate>

<asp:Label ID="projectGroupTypeID" runat="server" Text='<%#DataBinder.Eval(Container.DataItem, "Project_Group_Type_ID")%>' Visible="False" />

            </ItemTemplate>

</asp:TemplateColumn>

 

<asp:TemplateColumn HeaderText="" Visible="False">

                   <ItemTemplate>

<asp:Label ID="projectGroupID" runat="server" Text='<%# DataBinder.Eval(Container.DataItem, "Project_Group_ID")%>' Visible="False" />

            </ItemTemplate>

</asp:TemplateColumn>

 

In the details Datagrid, projectGroupTypeID and projectGroupID are used displayed on the itemtemplate but not visible to users. As these are used for edit and deleting operations.

 

</Columns>

</asp:DataGrid>

End of Inner DataGrid

</ItemTemplate>

End of ItemTemplare of Master DataGrid.

Start of EditItemTemplare for Master DataGrid.

And this is EditItemTemplate for this column when editing. So by another grid in the edititemtemplate you can see still see inner datagrid while editing master Datagrid.

<EditItemTemplate>

<asp:DataGrid ID="dgProjectGroup_Edit" AutoGenerateColumns="False" CellSpacing="0"

SkinID="datagridSkinID" CssClass="dataTable" BorderStyle="None" BorderWidth="0"

GridLines="None" CellPadding="0" Width="100%" runat="server" OnItemCommand="dgProjectGroup_ItemCommand"

            OnItemDataBound="dgProjectGroup_OnItemDataBound">

            <Columns>

`                  <asp:TemplateColumn HeaderText="">

<FooterStyle Font-Size="Small" Font-Bold="false" Wrap="false" BackColor="White" />

                             <ItemTemplate>

<asp:Label ID="projectGroupDescription" runat="server" Text='<%# DataBinder.Eval(Container.DataItem, "Project_Group_Description")%>'

                              Width="275px" />

                        </ItemTemplate>

 

                        <FooterTemplate>

<asp:TextBox ID="addProject" runat="Server" Text="" />

<asp:TextBox ID="addProjectTypeID" runat="Server" Text="" Visible="False" />

                        </FooterTemplate>

                  </asp:TemplateColumn>

            </Columns>

          </asp:DataGrid>

       </EditItemTemplate>

//end of EditItemTemplate

    </asp:TemplateColumn>

//end of TemplateColumn

    <asp:TemplateColumn>

          <ItemTemplate>

<asp:Button ID="cmdEditMeasure" runat="server" Text="Edit Category" CommandName="EditCategory" />

<asp:Button ID="cmdDeleteProjectGroupType" runat="server" Text="Delete Category" CommandName="DeleteCategory"

OnClientClick="return confirm('Are you sure you wish to Delete all?');" />

      </ItemTemplate>

      <EditItemTemplate>

<asp:Button ID="btnUpdateMeasure" runat="server" Text="Save Category" CommandName="SaveCategory" />

<asp:Button ID="cmdCancelEditProjectGroupType" runat="server" Text="Cancel Category" CommandName="CancelCategory" />

</EditItemTemplate>

<FooterStyle VerticalAlign="Middle"></FooterStyle>

<FooterTemplate>

<asp:Button ID="cmdAddCategory" CommandName="InsertCategory" runat="server" Text="Add Category" />

</FooterTemplate>

</asp:TemplateColumn>

Again in the Master datagrid, Iam displaying the Edit & delete buttons in an itemTemplate,displaying in save & cancel buttons in edit mode and displaying a add button on footer of the datagrid.

</Columns>

</asp:DataGrid>

End of master Datagrid.

The code File aspx.cs is follows .......

#region Variables

    private DataSet dsProject;

    private DataTable dsProjectGroupType;

    private DataTable dsProjectGroup;

    private ProjectGroupsAndTypes projectGroupsAndTypes;

    private string strprojectGroupTypeID;

    private int typeCount;

#endregion

/// <summary>

/// Handles the Load event of the Page control.

/// </summary>

/// <param name="sender">The source of the event.</param>

/// <param name="e">The <see cref="T:System.EventArgs"/> instance containing the event data.</param>

protected void Page_Load(object sender, EventArgs e)

    {

        try

        {                  

            projectGroupsAndTypes = new ProjectGroupsAndTypes();

            //The ProjectGroupsAndTypes is class which get does all //the operations such as getting records from

            //database,adding records to the database, deleting //records to the database etc,,,,

            //since is the effective way of taking the off code from //code behind file to bussiness service layer.

            //init the tables

            dsProjectGroupType = new DataTable();

            dsProjectGroup = new DataTable();

            //declare the projecttype and projectGroup tables

            typeCount = 0;

            strprojectGroupTypeID = string.Empty;

            if (!IsPostBack)

            {

                LoadData();

                //Bind the data tables to the DataGrid if it is not //postback

            }

        }

        catch (System.Exception exception)

        {

            throw exception;

        }

    }

 

#region "GridData Project Group"

    /// <summary>

    /// Loads the data.

    /// </summary>

    private void LoadData()

    {       

        try

        { 

            //Get the Records from projectsGroupType Table, and the

            //code to retrive the data is not shown here.As it is

            //general area and quite simple

            dsProjectGroupType = projectGroupsAndTypes.projectsGroupType();

            dsProjectGroupType.TableName = "Master";

            //Adding to the dataSet

            //Get Detail Table

            dsProjectGroup = projectGroupsAndTypes.projectGroup();

            dsProjectGroup.TableName = "Detail";

            //Declare new DataSet

            dsProject = new DataSet();

            //Adding to the dataSet

            dsProject.Tables.Add(dsProjectGroupType);

            //Adding to the dataSet

            //DataSet used for relations between Master and Details tables.

            dsProject.Tables.Add(dsProjectGroup);

            //create the relation between dataTables

            DataRelation relProjectGroups = new DataRelation("relProjectGroups",

                new DataColumn[] { dsProject.Tables["Master"].Columns["Project_Group_Type_ID"] },

                new DataColumn[] { dsProject.Tables["Detail"].Columns["Project_Group_Type_ID"] });

            // Add the Relation to the dataset

            dsProject.Relations.Add(relProjectGroups);

                   //assiging the dataSource to the dataGrid.

                   //Binding to the dataGrid (Master)

            dgProjectGroupType.DataSource = dsProject.Tables["Master"].DefaultView;

            dgProjectGroupType.DataBind();

        }

        catch (System.Exception exception)

        {

            throw exception;

        }

    }

 

/// <summary>

/// Handles the ItemDataBound event of the dgProjectGroupType control.

/// <param name="sender">The source of the event.</param>

/// <param name="e">The <see cref="T:System.Web.UI.WebControls.DataGridItemEventArgs"/> instance containing the event data.</param>

//Here is where the detail grid is binded with data Source.

//Here there are two cases when it is an  item or edititem.

//dgProjectGroup gets binds, when grid is not in edit mode.

//dgProjectGroup_Edit gets bind, when the gird is in edit mode.

//Note dgProjectGroup is again datagrid as dgProjectGroup.

protected void dgProjectGroupType_ItemDataBound(object sender, DataGridItemEventArgs e)

{

    if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem || e.Item.ItemType == ListItemType.EditItem)

        {

            DataRowView drvDesc = (DataRowView)e.Item.DataItem;

            if (e.Item.ItemType == ListItemType.EditItem)

            {

                // Bind the editable grid

                ((DataGrid)e.Item.FindControl("dgProjectGroup_Edit")).DataSource = drvDesc.CreateChildView("relProjectGroups");

                ((DataGrid)e.Item.FindControl("dgProjectGroup_Edit")).DataBind();

            }

            else

            {

                //binds the innergrid.         

                ((DataGrid)e.Item.FindControl("dgProjectGroup")).DataSource = drvDesc.CreateChildView("relProjectGroups");

                ((DataGrid)e.Item.FindControl("dgProjectGroup")).DataBind();

            }

        }

    }

 

/// Handles the ItemCommand event of the dgProjectGroupType control.

/// <param name="sender">The source of the event.</param>

/// <param name="e">The <see      cref="T:System.Web.UI.WebControls.DataGridCommandEventArgs"/> instance containing the event data.</param>

 

public void dgProjectGroupType_ItemCommand(object sender, DataGridCommandEventArgs e)

   {

    //Inserts the Project group Type in the Project Group Type Table

    if (e.CommandName == "InsertCategory")

    {

        string txtDescription = ((TextBox)e.Item.Cells[0].FindControl("addDescription")).Text;

        bool valid = true;

        if ((txtDescription.Equals(string.Empty)))

            valid = false;

        {

            //Whatever needed to be Done

            //Outer Grid actions.

        }

        LoadData();

        //Rebind the Grid

    }

    //Delete the Project group Type from the Project Group Type

    if (e.CommandName == "DeleteCategory")

    {

        int ProjectGroupTypeID = Convert.ToInt32(((Label)e.Item.FindControl("projectGroupTypeID")).Text);

        //Whatever is needed to perform Delete Action.

        //like projectGroupsAndTypes.delete(ProjectGroupTypeID)           

        LoadData();

        //Rebind the Grid

    }

    //edit the Grid

    if (e.CommandName == "EditCategory")

    {

        dgProjectGroupType.EditItemIndex = e.Item.ItemIndex;

        LoadData();

    }

    //Saves the category

    if (e.CommandName == "SaveCategory")

    {

        //get the ProjectGroupTypeID to edit the record in the table

        int ProjectGroupTypeID = Convert.ToInt32(((Label)(e.Item.Cells[1].Controls[1])).Text);

        //get the ProjectGroupType or description to edit the record in the table

        string ProjectGroupType = ((TextBox)e.Item.Cells[0].Controls[1]).Text;

        //Do what ever required to so update     

        //projectGroupsAndTypes.updateProjectGroupType(ProjectGroupTypeID, ProjectGroupType);

        //make Editable to reset and Bind the grid

        dgProjectGroupType.EditItemIndex = -1;

        LoadData();

    }

    //Cancel the action

    if (e.CommandName == "CancelCategory")

    {

        //make Editable to reset and Bind the grid

        dgProjectGroupType.EditItemIndex = -1;

        LoadData();

    }

}

    //This is the important Procedure.Because the master ProjectTypeID is always binded with details Datagrid on the footer.

    //So, whenever the a new record is added to the details grid the, we have the foreign key(ProjectTypeID).

    //But there is no way around, other than this which I found to be quite simple and effective.

    //On the footer event of ItemDataBoung, I am adding the ProjectTypeID to textBox(ID = addProjectTypeID).

    //Since this events fires for every record od master table.

    //I am increamenting the count(typeCount) such that detail table are matched to the master table.

    //And this happens for the first time.But this event is fired whenever other edit event is fired on detials datagrid.

    //And value stored in the textbox(ProjectTypeID) might be corrupted.

    //So solution to this is else part.assiging the value which is already available in the details dataGrid.         

 

public void dgProjectGroup_OnItemDataBound(object sender, DataGridItemEventArgs e)

{

    if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)

    {

        DataRowView drvDesc = (DataRowView)e.Item.DataItem;

        strprojectGroupTypeID = drvDesc.Row["Project_Group_Type_Id"].ToString();

    }

    else if (e.Item.ItemType == ListItemType.Footer)

    {

        if (strprojectGroupTypeID.Equals(string.Empty))

        {

            ((TextBox)e.Item.FindControl("addProjectTypeID")).Text = Convert.ToString((((DataTable)

            projectGroupsAndTypes.projectsGroupType(programmeID)).Rows[typeCount])[0]);

        }

        else

        {

            ((TextBox)e.Item.FindControl("addProjectTypeID")).Text = strprojectGroupTypeID;

            strprojectGroupTypeID = "";

        }

        typeCount++;

    }

}

    /// Handles the ItemCommand event of the dgProjectGroup control.

    /// /// </summary>

    /// /// <param name="sender">The source of the event.</param>

    /// /// <param name="e">The <see                   cref="T:System.Web.UI.WebControls.DataGridCommandEventArgs"/>

    instance containing the event data.</param>   

 

public void dgProjectGroup_ItemCommand(object sender, DataGridCommandEventArgs e)

{

    //insert new record

    if (e.CommandName == "InsertGroup")

    {

        int projectGroupTypeID = Convert.ToInt32(((TextBox)e.Item.FindControl("addProjectTypeID")).Text);

        string txtinnerDescription = ((TextBox)e.Item.FindControl("addProject")).Text;

        bool valid = true;

        if ((txtinnerDescription.Equals(string.Empty)))

            valid = false;

        //Do ever is req here.or something like this.

        //projectGroupsAndTypes.AddProjectGroup

        //(projectGroupTypeID, txtinnerDescription);

        //Load and rebind the data

        LoadData();

    }

        //Delete the Record

    else if (e.CommandName == "DeleteGroup")

    {

        int projectGroupID = Convert.ToInt32(((Label)(e.Item.FindControl("projectGroupID"))).Text);

        //SomeCode to delete the projectGroupID

        projectGroupsAndTypes.DeleteProjectGroup(projectGroupID)

        //Bind and rebind the data

        LoadData();

    }

        //edits inner group

    else if (e.CommandName == "EditGroup")

    {

        //Another UserCode Goes here

        //Declare a temporary dataGrid and get referred to details datagrid.

        //Assingn the dataGird editItemIdex with Itemindex.

        DataGrid tmpDg = (DataGrid)sender;

        tmpDg.EditItemIndex = (int)e.Item.ItemIndex;

        //delcare A dataview and get all records of the details //table.

        //And now filter the dataview with the //Project_Group_Type_ID (foreign key in the details //table and primary in the

        master table)

        DataView dv = new DataView();

        dv = projectGroupsAndTypes.projectGroup(programmeID).DefaultView;

        dv.Sort = "Project_Group_Type_ID";

        //The Project_Group_Type_ID is obtained by the following code.

        object objExpr = ((Label)e.Item.FindControl("projectGroupTypeID")).Text;

        //Now assigning the filtered dataview back to the datagrid(ref as detail dataGrid)

        tmpDg.DataSource = dv.FindRows(objExpr);

        tmpDg.DataBind();

    }

        // saves edited data

    else if (e.CommandName == "SaveGroup")

    {

        int emp_id = e.Item.ItemIndex;

        DataGrid tmpDg = (DataGrid)sender;

        //retriving the ProjectGroupID from hidden control

        int ProjectGroupID = Convert.ToInt32(((Label)e.Item.FindControl("projectGroupID")).Text);

        //retriving the ProjectGroup from hidden control

        string ProjectGroup = ((TextBox)e.Item.FindControl("txtGroup")).Text;

        //performing some action to save

        projectGroupsAndTypes.updateProjectGroup(ProjectGroupID, ProjectGroup);

        //cancelling the edit eventby setting edititemindex to -1

        tmpDg.EditItemIndex = -1;

        //delcare A dataview and get all records of the details //table.

        DataView dv = projectGroupsAndTypes.projectGroup(programmeID).DefaultView;

        dv.Sort = "Project_Group_Type_ID";

        //The Project_Group_Type_ID is obtained by the following code.

        object objExpr = ((Label)e.Item.FindControl("projectGroupTypeID")).Text;

        //Now assigning the filtered dataview back to the datagrid(ref as detail dataGrid)

        tmpDg.DataSource = dv.FindRows(objExpr);

        tmpDg.DataBind();

    }

        //cancel the action

    else if (e.CommandName == "CancelGroup")

    {

        DataGrid tmpDg = (DataGrid)sender;

        tmpDg.EditItemIndex = -1;

        //delcare A dataview and get all records of the details //table.

        DataView dv = projectGroupsAndTypes.projectGroup(programmeID).DefaultView;

        dv.Sort = "Project_Group_Type_ID";

        //The Project_Group_Type_ID is obtained by the following code.

        object objExpr = ((Label)e.Item.FindControl("projectGroupTypeID")).Text;

        //Now assigning the filtered dataview back to the datagrid(ref as detail dataGrid)

        tmpDg.DataSource = dv.FindRows(objExpr);

        tmpDg.DataBind();

    }

}  

#endregion

COMMENT USING

Trending up