Master Detail DataGridView in C# Windows Forms

Introduction



In my previous article I explained how to Create a DatagGridView helper class using C#

I have extended the DatagGridView Helper class to create a Master/Detail DatagGridView. My intent is to create a simple and easy program for users. Users can download the code and can customize it depending on their requirements.

Why to use a Nested or Hierarchical DataGridView

In real projects like Order Management, Production Management and and so on we need to display the data in the hierarchical result.

For example let's use an Order Management project for a restaurant. Let's consider four people going to a restaurant to have their lunch. The waiter from the restaurant will provide a menu card to select the item to place an order. Now in a table the total of 4 people are sitting in a restaurant. In restaurant management, usually all the tables have a unique Table Id or name. All 4 people will select their item from the menu and place the order to serve their food. In restaurant management for each order we will create a unique id in an Order Master table and all the item details related to the order in the Order Detail table. Let's see an example structure of the order.

Why to use a Master and Detail Table
 
To avoid the duplicate data we can use the master Detail table relation to store our data. For example for every order there will be one waiter and one Table so if we didn't use the Master Detail table relation then the output will be like this below.



Here we can see that Order No, Table ID, Waiter Name and Order Date have been repeated. To avoid this duplicate data we will create a Master and Detail relation tables. See the following table for Master and Details.

Order Master Table

Here we can see that the duplicate data has been stored in a separate table as an Order Master Table.



Order Detail Table

Here we can see all the item details of the order in a separate table. But in the detail table we have used the Order Number for a relation to the Master table. Using the relation we can combine both tables and produce the output.



Normal grid result

The result can be shown without using the Hierarchal grid output. But we must display the duplicate results as in the following.



We can also merge the same data and show the result as in the following table. But the output is not much better and is not easy to view and understand.



Let's see now the hierarchical output of the same result.



Now this final result looks much better than all the previous. It will be easy to view the master and detail of all records. Here is my sample output of the hierarchical DataGridView.



In the same manner as Order Management in restaurant projects we also have Bill Master and Detail, Account Master and Detail, Item Master and Detail and Inventory Master and Detail. In production projects we will have Production Order Master and Oder Detail, Finished Good Receipt Master and Detail, Finished Goods Issue Master and Detail and so on. In the same manner in our all our actual projects we will use the Master and detail relation to display our data.

Using the code

As I explained in this article, I have used and extended my DataGridView helper class to create a Nested DataGridView. You can view my DataGridView helper class details from my article.

In my DGVhelper class I have added the following functionality to create the nested grid.
  • ImageCoulmn 
  • DGVMasterGridClickEvents 
  • DGVDetailGridClickEvents 
The user can use all the events, like CellClick, CellContentClick and and so on for both the Master and Detail grid.

I have created two separate list classes to populate the master and detail results. In the form load I called the method to add the details to each list class.

I have created both a Master and Detail DataGridView programmatically (dynamically) using my ShanuDGVHelper Class.

Master Grid Setting: In Form Load I have called this method to create a master DataGridView at runtime. In my code I add the comments before each line to explain its use.
  1. // to generate Master Datagridview with your coding    
  2. public void MasterGrid_Initialize()   
  3. {  
  4.   
  5.     //First generate the grid Layout Design    
  6.     Helper.ShanuDGVHelper.Layouts(Master_shanuDGV, Color.LightSteelBlue, Color.AliceBlue, Color.WhiteSmoke, false, Color.SteelBlue, falsefalsefalse);  
  7.   
  8.     //Set Height,width and add panel to your selected control    
  9.     Helper.ShanuDGVHelper.Generategrid(Master_shanuDGV, pnlShanuGrid, 1000, 600, 10, 10);  
  10.   
  11.   
  12.     // Color Image Column creation    
  13.     Helper.ShanuDGVHelper.Templatecolumn(Master_shanuDGV, ShanuControlTypes.ImageColumn, "img"""""true, 26, DataGridViewTriState.True, DataGridViewContentAlignment.MiddleCenter, DataGridViewContentAlignment.MiddleRight, Color.Transparent, null"""", Color.Black);  
  14.   
  15.     // BoundColumn creation    
  16.     Helper.ShanuDGVHelper.Templatecolumn(Master_shanuDGV, ShanuControlTypes.BoundColumn, "Order_No""Order NO""Order NO"true, 90, DataGridViewTriState.True, DataGridViewContentAlignment.MiddleLeft, DataGridViewContentAlignment.MiddleCenter, Color.Transparent, null"""", Color.Black);  
  17.   
  18.     // BoundColumn creation    
  19.     Helper.ShanuDGVHelper.Templatecolumn(Master_shanuDGV, ShanuControlTypes.BoundColumn, "Table_ID""Table ID""Table ID"true, 80, DataGridViewTriState.True, DataGridViewContentAlignment.MiddleLeft, DataGridViewContentAlignment.MiddleCenter, Color.Transparent, null"""", Color.Black);  
  20.   
  21.   
  22.     // BoundColumn creation    
  23.     Helper.ShanuDGVHelper.Templatecolumn(Master_shanuDGV, ShanuControlTypes.BoundColumn, "Description""Description""Description"true, 320, DataGridViewTriState.True, DataGridViewContentAlignment.MiddleLeft, DataGridViewContentAlignment.MiddleCenter, Color.Transparent, null"""", Color.Black);  
  24.   
  25.   
  26.     // BoundColumn creation    
  27.     Helper.ShanuDGVHelper.Templatecolumn(Master_shanuDGV, ShanuControlTypes.BoundColumn, "Order_DATE""Order DATE""Order DATE"true, 140, DataGridViewTriState.True, DataGridViewContentAlignment.MiddleCenter, DataGridViewContentAlignment.MiddleCenter, Color.Transparent, null"""", Color.Black);  
  28.   
  29.   
  30.     // BoundColumn creation    
  31.     Helper.ShanuDGVHelper.Templatecolumn(Master_shanuDGV, ShanuControlTypes.BoundColumn, "Waiter_ID""Waiter_ID""Waiter_ID"true, 120, DataGridViewTriState.True, DataGridViewContentAlignment.MiddleLeft, DataGridViewContentAlignment.MiddleCenter, Color.Transparent, null"""", Color.Black);  
  32.   
  33.   
  34.     //Convert the List to DataTable    
  35.     DataTable detailTableList = ListtoDataTable(DataClass.OrderDetailBindClass.objDetailDGVBind);  
  36.   
  37.     // Image Colum Click Event - In  this method we create an event for cell click and we will display the Detail grid with result.    
  38.   
  39.     objshanudgvHelper.DGVMasterGridClickEvents(Master_shanuDGV, Detail_shanuDGV, Master_shanuDGV.Columns["img"].Index, ShanuEventTypes.cellContentClick, ShanuControlTypes.ImageColumn, detailTableList, "Order_No");  
  40.   
  41.     // Bind data to DGV.    
  42.     Master_shanuDGV.DataSource = DataClass.OrderMasterBindClass.objMasterDGVBind;  
  43.   
  44. }  
Cell Click Event: I have called this the preceding method to create a Cell click event for the master DataGridView.
  1. // Image Colum Click Event - In  this method we create an event for cell click and we will display the Detail grid with result.    
  2. bjshanudgvHelper.DGVMasterGridClickEvents(Master_shanuDGV, Detail_shanuDGV, Master_shanuDGV.Columns["img"].Index, ShanuEventTypes.cellContentClick, ShanuControlTypes.ImageColumn, detailTableList, "Order_No");  
This event will be used for the master grid image click event. In this event I will get the Order Number and filter the result from DataTabledetail. Display the final Dataview result to the detail DataGridView.
  1. // Image Colukmn Click evnet    
  2. #region Image Colukmn Click Event  
  3. public void DGVMasterGridClickEvents(DataGridView ShanuMasterDGV, DataGridView ShanuDetailDGV, int columnIndexs, ShanuEventTypes eventtype, ShanuControlTypes types, DataTable DetailTable, String FilterColumn)  
  4. {  
  5.     MasterDGVs = ShanuMasterDGV;  
  6.     DetailDGVs = ShanuDetailDGV;  
  7.     gridColumnIndex = columnIndexs;  
  8.     DetailgridDT = DetailTable;  
  9.     FilterColumnName = FilterColumn;  
  10.   
  11.     MasterDGVs.CellContentClick += new DataGridViewCellEventHandler(masterDGVs_CellContentClick_Event);  
  12. }  
  13. private void masterDGVs_CellContentClick_Event(object sender, DataGridViewCellEventArgs e)   
  14. {  
  15.     DataGridViewImageColumn cols = (DataGridViewImageColumn) MasterDGVs.Columns[0];  
  16.   
  17.     // cols.Image = Image.FromFile(ImageName);    
  18.     MasterDGVs.Rows[e.RowIndex].Cells[0].Value = Image.FromFile("expand.png");  
  19.   
  20.     if (e.ColumnIndex == gridColumnIndex)  
  21.     {  
  22.         if (ImageName == "expand.png")  
  23.         {  
  24.             DetailDGVs.Visible = true;  
  25.             ImageName = "toggle.png";  
  26.             // cols.Image = Image.FromFile(ImageName);    
  27.             MasterDGVs.Rows[e.RowIndex].Cells[e.ColumnIndex].Value = Image.FromFile(ImageName);  
  28.   
  29.   
  30.             String Filterexpression = MasterDGVs.Rows[e.RowIndex].Cells[FilterColumnName].Value.ToString();  
  31.   
  32.             MasterDGVs.Controls.Add(DetailDGVs);  
  33.   
  34.             Rectangle dgvRectangle = MasterDGVs.GetCellDisplayRectangle(1, e.RowIndex, true);  
  35.             DetailDGVs.Size = new Size(MasterDGVs.Width - 200, 200);  
  36.             DetailDGVs.Location = new Point(dgvRectangle.X, dgvRectangle.Y + 20);  
  37.   
  38.   
  39.             DataView detailView = new DataView(DetailgridDT);  
  40.             detailView.RowFilter = FilterColumnName + " = '" + Filterexpression + "'";  
  41.             if (detailView.Count <= 0) {  
  42.                 MessageBox.Show("No Details Found");  
  43.             }  
  44.             DetailDGVs.DataSource = detailView;  
  45.   
  46.   
  47.         }   
  48.         else   
  49.         {  
  50.             ImageName = "expand.png";  
  51.             //  cols.Image = Image.FromFile(ImageName);    
  52.             MasterDGVs.Rows[e.RowIndex].Cells[e.ColumnIndex].Value = Image.FromFile(ImageName);  
  53.             DetailDGVs.Visible = false;  
  54.         }  
  55.     }   
  56.     else   
  57.     {  
  58.         DetailDGVs.Visible = false;  
  59.   
  60.     }  
  61. }#endregion  
In the cell click event if the image column is clicked then I will change the image to Expand and Collapse depending on the selected image name. If the image is selected to Expand then I will make the detail DataGridView visible.

In the cell click event I will get something for the current selected Order Number. This order number will be used in “DataView” to filter only the selected order result. The final result will be bound to the detail DataGridView.

Detail Grid Setting: In the Form load I have called this method to create a detail DataGridView at runtime.

In my code I added comments before each line to explain its use.
  1. // to generate Detail Datagridview with your coding    
  2. public void DetailGrid_Initialize()   
  3. {  
  4.   
  5.     //First generate the grid Layout Design    
  6.     Helper.ShanuDGVHelper.Layouts(Detail_shanuDGV, Color.Peru, Color.Wheat, Color.Tan, false, Color.Sienna, falsefalsefalse);  
  7.   
  8.     //Set Height,width and add panel to your selected control    
  9.     Helper.ShanuDGVHelper.Generategrid(Detail_shanuDGV, pnlShanuGrid, 800, 200, 10, 10);  
  10.   
  11.     // Color Dialog Column creation    
  12.     Helper.ShanuDGVHelper.Templatecolumn(Detail_shanuDGV, ShanuControlTypes.BoundColumn, "Order_Detail_No""Detail No""Order Detail No"true, 90, DataGridViewTriState.True, DataGridViewContentAlignment.MiddleCenter, DataGridViewContentAlignment.MiddleRight, Color.Transparent, null"""", Color.Black);  
  13.   
  14.     // BoundColumn creation    
  15.     Helper.ShanuDGVHelper.Templatecolumn(Detail_shanuDGV, ShanuControlTypes.BoundColumn, "Order_No""Order NO""Order NO"true, 80, DataGridViewTriState.True, DataGridViewContentAlignment.MiddleLeft, DataGridViewContentAlignment.MiddleCenter, Color.Transparent, null"""", Color.Black);  
  16.   
  17.     // BoundColumn creation    
  18.     Helper.ShanuDGVHelper.Templatecolumn(Detail_shanuDGV, ShanuControlTypes.BoundColumn, "Item_Name""Item_Name""Item_Name"true, 160, DataGridViewTriState.True, DataGridViewContentAlignment.MiddleLeft, DataGridViewContentAlignment.MiddleCenter, Color.Transparent, null"""", Color.Black);  
  19.   
  20.   
  21.     // BoundColumn creation    
  22.     Helper.ShanuDGVHelper.Templatecolumn(Detail_shanuDGV, ShanuControlTypes.BoundColumn, "Notes""Notes""Notes"true, 260, DataGridViewTriState.True, DataGridViewContentAlignment.MiddleLeft, DataGridViewContentAlignment.MiddleCenter, Color.Transparent, null"""", Color.Black);  
  23.   
  24.   
  25.     // BoundColumn creation    
  26.     Helper.ShanuDGVHelper.Templatecolumn(Detail_shanuDGV, ShanuControlTypes.BoundColumn, "Price""Price""Price"true, 70, DataGridViewTriState.True, DataGridViewContentAlignment.MiddleRight, DataGridViewContentAlignment.MiddleCenter, Color.Transparent, null"""", Color.Black);  
  27.   
  28.   
  29.     // BoundColumn creation    
  30.     Helper.ShanuDGVHelper.Templatecolumn(Detail_shanuDGV, ShanuControlTypes.BoundColumn, "QTY""QTY""QTY"true, 40, DataGridViewTriState.True, DataGridViewContentAlignment.MiddleRight, DataGridViewContentAlignment.MiddleCenter, Color.Transparent, null"""", Color.Black);  
  31.   
  32.   
  33.     objshanudgvHelper.DGVDetailGridClickEvents(Detail_shanuDGV);  
  34. }  
Detail Grid Cell Click Event: I have called this the preceding method to create a Cell click event for the detail DataGridView.
  1. objshanudgvHelper.DGVDetailGridClickEvents(Detail_shanuDGV);  
This event will be used for the detail grid Cell Click event. In the cell click of the Detail grid I will get each cell text and display it in a Messagebox.
  1. public void DGVDetailGridClickEvents(DataGridView ShanuDetailDGV)   
  2. {  
  3.     DetailDGVs = ShanuDetailDGV;  
  4.     DetailDGVs.CellContentClick += new DataGridViewCellEventHandler(detailDGVs_CellContentClick_Event);  
  5. }  
  6. private void detailDGVs_CellContentClick_Event(object sender, DataGridViewCellEventArgs e)   
  7. {  
  8.     MessageBox.Show("Detail grid Clicked : You clicked on " + DetailDGVs.Rows[e.RowIndex].Cells[e.ColumnIndex].Value);  
  9. }