Master Detail GridView with Insert Option






4.41/5 (12 votes)
GridView inside GridView with master-detail edit, delete, and insert options.
Introduction
I had to implement a Master-Detail GridView in my application. Searching the net, I did find a lot of solutions, but couldn’t find one where the child table was positioned properly. Well, there might be other solutions that give the same result, but I thought sharing this might help others.
What I have done
I’ve extended the SearchGridView
(the last article I posted) and created a NestableGridView
class. I overrode the RenderContents
function to render the child table in a separate row.
The code
I’ve extended the SearchGridView
control as a NestableGridView
.
public class NestableGridView : SearchGridView
I’ve overrode the RenderContents
function to identify the cell where the child table is and to render it in a separate row.
protected override void RenderContents(HtmlTextWriter writer)
{
//If there are no rows to be rendered
if (DesignMode || Rows.Count == 0)
{
base.RenderContents(writer);
return;
}
//Render the begin tag
base.RenderBeginTag(writer);
//Render header row
if(HeaderRow != null)
HeaderRow.RenderControl(writer);
foreach (GridViewRow row in Rows)
{
Control childCtl = row.FindControl(ChildTableID);
//Render child row by custom method if the child control is visible
if (childCtl != null && childCtl.Visible)
{
row.RenderBeginTag(writer);
TableCell childCell = null;
foreach (TableCell cell in row.Cells)
{
if (cell.Controls.IndexOf(childCtl) == -1)
cell.RenderControl(writer);
else
{
//If this is the child cell close the table cell
writer.Write("<"+"td"+"><"+"/td"+">");
childCell = cell;
}
}
//Child control needs to be rendered in the next row
if(childCell != null)
{
writer.Write("<"+"/tr"+"><"+"tr"+">");
childCell.ColumnSpan = row.Cells.Count;
childCell.Attributes.Add("align",ChildTableAlign.ToString());
childCell.RenderControl(writer);
}
row.RenderEndTag(writer);
}
else
{
//If the child control is not visible, render thr row
row.RenderControl(writer);
}
}
//Render Footer Row
if (FooterRow != null)
FooterRow.RenderControl(writer);
//Render Pager Row
if (PagerRow != null)
PagerRow.RenderControl(writer);
base.RenderEndTag(writer);
}
The SelectedIndexChanging
event handles the toggling visibility of the child table.
protected override void OnSelectedIndexChanging(GridViewSelectEventArgs e)
{
base.OnSelectedIndexChanging(e);
if (DesignMode)
return;
if (Rows[e.NewSelectedIndex] != null &&
Rows[e.NewSelectedIndex].FindControl(ChildTableID) != null)
{
Control childCtl = Rows[e.NewSelectedIndex].FindControl(ChildTableID);
if (childCtl != null)
childCtl.Visible = !childCtl.Visible;
}
}
Working sample
Now, let me illustrate the above control with the help of an example. For this purpose, I have used the Categories and Products table from the NorthWind database.
- Step 1: Create a datasource
dsMaster
withselect query "SELECT * From Categories"
. - Step 2 : Create an instance of
NestableGridView
and customize theSearchFilters
property to have the list of columns on which the search can be performed. - Step 3: Create a template column with a
SearchGridView
with the datasourcedsChild
and a hidden field_hfChildSearch
to hold the search string of the child table. Set theVisibility
of thePanel
tofalse
to hide all child tables, ortrue
to show all tables initially. - Step 4: Set the child table ID of the master grid as
pnlChild
(the ID of the child table panel). - Step 5: Implement the
SearchGrid
event on the master and child tables to filter and search records. - Step 6: Add empty data templates to the master and child tables to insert new records.
- Step 7: Implement the
AddRow
event on the master and child tables to add new records to the tables.
Conclusion
NestableGridView
can be used not only to display child tables but any control inside the master row, like pictures etc. Also, the alignment of the child row can be set using the ChildTableAlign
attribute.