Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / desktop / WinForms

Nested DataGridView in Windows Forms C#

4.78/5 (48 votes)
20 Jan 2015CPOL5 min read 173.3K   16.2K  
Nested or Master Detail or Hierarchical DataGridView for Winforms

Image 1

Introduction

In my previous article, I explained how to create a DatagGridView helper class using C#.

I extended the DatagGridView Helper class to create a Nested DatagGridView. Few days ago, one CodeProject member asked a question on how to create a Nested or Master Detail or Hierarchical DataGridView for WinForms. I started searching in Google, but didn’t get any result for Nested DataGridView. I started working on creating a Nested DataGridView sample program which should be useful to all. As a result, I created a Nested DataGridView, and you can find the source code from the link at the top of this article. My aim was to create a simple and easy program for users. Users can download the code and customize depending on their requirement.

Why We Need Nested or Hierarchical Datagridview

In real time projects like Order Management, Production Management, etc., we need to display the data in the hierarchical result.

For example, let’s take Order Management project for a restaurant. Let’s consider that four people go to a restaurant to have their lunch. The waiter from the restaurant will give a menu card to select the item to place an order. Now at a Table, a total of four people are sitting. In a restaurant management usually for all tables, there will be a unique Table Id or name. All four people will select their item needed from the menu card 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 Order Detail table. Let’s see an example structure of the order.

Why We Need Master and Detail Table?

To avoid 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, the output will be like this below:

Image 2

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 below table for Master and Details.

Order Master Table

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

Image 3

Order Detail Table

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

Image 4

Normal Grid Result

The result can be shown without using the Hierarchical grid output. But we have to display the duplicate result as below:

Image 5

We can also merge the same data and show the result like this below table. But the output is not very good and not easy to view and understand.

Image 6

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

Image 7

Now this final result looks much better than all. It will be easy to view the master and detail of all records.

Here is my sample output of hierarchical Datagridview.

Image 8

Same like Order Management in Restaurant projects, we will have Bill Master and Detail, Account Master and Detail, Item Master and Detail, Inventory Master and Detail. In production projects, we will have Production Order Master and Order Detail, Finished Good Receipt Master and Detail, Finished Goods Issue Master and Detail, etc. Similar to this in all our real time projects, we will use the Master and detail relation to display our data.

Using the Code

As I told you, 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 below functionality to create the nested grid:

  • ImageCoulmn
  • DGVMasterGridClickEvents
  • DGVDetailGridClickEvents

User can use all events like CellClick, CellContentClick, etc. for both Master and Detail grid.

I have created two separate list class to populate the master and detail result. In form load, call the method to add the details to each list class.

I have created both 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.

C#
// to generate Master Datagridview with your coding
     public void MasterGrid_Initialize()
     {
         //First generate the grid Layout Design
         Helper.ShanuDGVHelper.Layouts(Master_shanuDGV, Color.LightSteelBlue,
         Color.AliceBlue, Color.WhiteSmoke, false, Color.SteelBlue, false, false, false);

         //Set Height ,width and add panel to your selected control
         Helper.ShanuDGVHelper.Generategrid
                (Master_shanuDGV, pnlShanuGrid, 1000, 600, 10, 10);

         // Color Image Column creation
         Helper.ShanuDGVHelper.Templatecolumn(Master_shanuDGV,
         ShanuControlTypes.ImageColumn, "img", "", "", true, 26,
         DataGridViewTriState.True, DataGridViewContentAlignment.MiddleCenter,
         DataGridViewContentAlignment.MiddleRight, Color.Transparent, null,
         "", "", Color.Black);

         // BoundColumn creation
         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);

         // BoundColumn creation
         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);

         // BoundColumn creation
         Helper.ShanuDGVHelper.Templatecolumn(Master_shanuDGV,
         ShanuControlTypes.BoundColumn, "Description", "Description", "Description",
         true, 320, DataGridViewTriState.True, DataGridViewContentAlignment.MiddleLeft,
         DataGridViewContentAlignment.MiddleCenter, Color.Transparent, null,
         "", "", Color.Black);

         // BoundColumn creation
         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);

         // BoundColumn creation
         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);

         //Convert the List to DataTable
         DataTable detailTableList = ListtoDataTable
         (DataClass.OrderDetailBindClass.objDetailDGVBind);

         // Image Column Click Event - In  this method we create an event for
         // cell click and we will display the Detail grid with result.

         objshanudgvHelper.DGVMasterGridClickEvents(Master_shanuDGV,
         Detail_shanuDGV, Master_shanuDGV.Columns["img"].Index,
         ShanuEventTypes.cellContentClick, ShanuControlTypes.ImageColumn,
         detailTableList, "Order_No");

         // Bind data to DGV.
         Master_shanuDGV.DataSource = DataClass.OrderMasterBindClass.objMasterDGVBind;
     }

Cell Click Event

I have called this above method to create a Cell click event for master DataGridView.

C#
// Image Column Click Event - In  this method we create an event for
// cell click and we will display the Detail grid with result.
objshanudgvHelper.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 No and filter the result from DataTabledetail. Display the final Dataview result to Detail DataGridView.

C#
public void DGVMasterGridClickEvents(DataGridView ShanuMasterDGV,
DataGridView ShanuDetailDGV, int columnIndexs, ShanuEventTypes eventtype,
ShanuControlTypes types,DataTable DetailTable,String FilterColumn)
      {
          MasterDGVs = ShanuMasterDGV;
          DetailDGVs = ShanuDetailDGV;
          gridColumnIndex = columnIndexs;
          DetailgridDT = DetailTable;
          FilterColumnName = FilterColumn;

          MasterDGVs.CellContentClick += new DataGridViewCellEventHandler
                                         (masterDGVs_CellContentClick_Event);
      }
      private void masterDGVs_CellContentClick_Event
              (object sender, DataGridViewCellEventArgs e)
      {
          DataGridViewImageColumn cols = (DataGridViewImageColumn)MasterDGVs.Columns[0];

         // cols.Image = Image.FromFile(ImageName);
          MasterDGVs.Rows[e.RowIndex].Cells[0].Value = Image.FromFile("expand.png");

           if (e.ColumnIndex == gridColumnIndex)
           {
               if (ImageName == "expand.png")
               {
                   DetailDGVs.Visible = true;
                   ImageName = "toggle.png";
                   // cols.Image = Image.FromFile(ImageName);
                   MasterDGVs.Rows[e.RowIndex].Cells[e.ColumnIndex].Value =
                                                     Image.FromFile(ImageName);

                   String Filterexpression = MasterDGVs.Rows[e.RowIndex].Cells
                                             [FilterColumnName].Value.ToString();

                   MasterDGVs.Controls.Add(DetailDGVs);

                   Rectangle dgvRectangle = MasterDGVs.GetCellDisplayRectangle
                                            (1, e.RowIndex, true);
                   DetailDGVs.Size = new Size(MasterDGVs.Width - 200, 200);
                   DetailDGVs.Location = new Point(dgvRectangle.X, dgvRectangle.Y + 20);

                   DataView detailView = new DataView(DetailgridDT);
                   detailView.RowFilter = FilterColumnName +
                                          " = '" + Filterexpression + "'";
                   if (detailView.Count <= 0)
                   {
                       MessageBox.Show("No Details Found");
                   }
                   DetailDGVs.DataSource = detailView;
               }
               else
               {
                   ImageName = "expand.png";
                   //  cols.Image = Image.FromFile(ImageName);
                   MasterDGVs.Rows[e.RowIndex].Cells[e.ColumnIndex].Value =
                                                         Image.FromFile(ImageName);
                   DetailDGVs.Visible = false;
               }
           }
           else
           {
               DetailDGVs.Visible = false;
           }
      }

In cell click event, if the image column is clicked, 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 visible of the detail DataGridView.

In cell click event, I will get for the current selected Order No. This Order No 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 Form load, I have called this method to create a Detail DataGridView at runtime.

In my code, I add the comments before each line to explain its use.

C#
// to generate Detail Datagridview with your coding
public void DetailGrid_Initialize()
{
    //First, generate the grid Layout Design
    Helper.ShanuDGVHelper.Layouts(Detail_shanuDGV, Color.Peru,
    Color.Wheat, Color.Tan, false, Color.Sienna, false, false, false);

    //Set Height, width and add panel to your selected control
    Helper.ShanuDGVHelper.Generategrid
          (Detail_shanuDGV, pnlShanuGrid, 800, 200, 10, 10);

    // Color Dialog Column creation
    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);

    // BoundColumn creation
    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);

    // BoundColumn creation
    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);

    // BoundColumn creation
    Helper.ShanuDGVHelper.Templatecolumn(Detail_shanuDGV,
    ShanuControlTypes.BoundColumn, "Notes", "Notes", "Notes", true, 260,
    DataGridViewTriState.True, DataGridViewContentAlignment.MiddleLeft,
    DataGridViewContentAlignment.MiddleCenter, Color.Transparent,
    null, "", "", Color.Black);

    // BoundColumn creation
    Helper.ShanuDGVHelper.Templatecolumn(Detail_shanuDGV,
    ShanuControlTypes.BoundColumn, "Price", "Price", "Price", true, 70,
    DataGridViewTriState.True, DataGridViewContentAlignment.MiddleRight,
    DataGridViewContentAlignment.MiddleCenter, Color.Transparent, null,
    "", "", Color.Black);

    // BoundColumn creation
    Helper.ShanuDGVHelper.Templatecolumn
    (Detail_shanuDGV, ShanuControlTypes.BoundColumn, "QTY", "QTY", "QTY",
    true, 40, DataGridViewTriState.True, DataGridViewContentAlignment.MiddleRight,
    DataGridViewContentAlignment.MiddleCenter, Color.Transparent, null,
    "", "", Color.Black);
    objshanudgvHelper.DGVDetailGridClickEvents(Detail_shanuDGV);
}

Detail Grid Cell Click Event

I have called this above method to create a Cell click event for Detail DataGridView.

C#
objshanudgvHelper.DGVDetailGridClickEvents(Detail_shanuDGV);

This event will be used for the Detail grid Cell Click Event. In cell click of Detail grid, I will get each cell text and display in the Messagebox.

C#
  public void DGVDetailGridClickEvents(DataGridView ShanuDetailDGV)
    {
        DetailDGVs = ShanuDetailDGV;

        DetailDGVs.CellContentClick += new DataGridViewCellEventHandler
                                       (detailDGVs_CellContentClick_Event);
    }
      private void detailDGVs_CellContentClick_Event(object sender,
                                         DataGridViewCellEventArgs e)
      {
          MessageBox.Show("Detail grid Clicked : You clicked on " +
                     DetailDGVs.Rows[e.RowIndex].Cells[e.ColumnIndex].Value);
      }
}

Image 9

Points of Interest

This program explains the basic functions to create single level Hierarchical DataGridView. This same functionality can be used to create multi level Hierarchical DataGridView.

History

  • 2nd December, 2014: Version 1.0

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)