Many data have parent nodes and child nodes. We hope that when we click the parent node, we can expand the child node data under the parent node.
For example, in a hospital department table, there are father department and child department. After clicking on the father department, all child departments under the department can be displayed below the father department.
Let's talk about how to implement this function in DataGridView.
First, create sample data:
Sample Data SQL
create table Department ( ID int identity(1,1) not null, DName varchar(20) null, DparentId int null, Dtelphone varchar(20) null, Dhospital varchar(50) null ) insert into Department values('Outdoor Room',1,'1111','XXX Hospital') insert into Department values('Outpatient Internal Medicine',1,'2222','XXX Hospital') insert into Department values('Outpatient surgery',1,'3333','XXX Hospital') insert into Department values('Outpatient Pediatrics',1,'4444','XXX Hospital') insert into Department values('Neural Inner Unit',2,'5555','XXX Hospital') insert into Department values('Neurosurgery',2,'6666','XXX Hospital') insert into Department values('Inpatient surgery',2,'7777','XXX Hospital') insert into Department values('Inpatient Rehabilitation',2,'8888','XXX Hospital')
In fact, the idea is very simple. When expanding the parent node, insert a new DataGridViewRow under the parent node; when shrinking the parent node, delete the DataGridViewRow of the child node under the parent node.
For simplicity, I hardcoded the data reading in the code directly.
Loading the parent node data, in addition to the columns in the database, I also added two new columns: IsEx and EX.
private void DataGridBing(DataTable table) { if ( > 0) { for (int i = 0; i < ; i++) { int k = this.(); DataGridViewRow row = this.[k]; ["ID"].Value = [i]["ID"]; ["DName"].Value = [i]["DName"]; ["Daddress"].Value = [i]["Daddress"]; ["Dtelphone"].Value = [i]["Dtelphone"]; // Used to show whether the line has been expanded ["IsEx"].Value = "false"; // Used to display expanded or shrink symbols. For simplicity, I just use strings. In fact, the pictures are more beautiful ["EX"].Value = "+"; } } }
The following is the Cell click event, which writes the expanded insertion and shrinking delete in the event.
Insert child nodes:
string isEx=this.[].Cells["IsEx"].(); if (this.[].Name == "EX" && isEx=="false") { string id = this.[].Cells["ID"].(); DataTable table = GetDataTable("select * from Department where DparentId="+id); if ( > 0) { //Insert row this.(+1, ); for (int i = 0; i < ; i++) { DataGridViewRow row = this.[ + i+1]; = ; ["ID"].Value = [i]["ID"]; ["DName"].Value = [i]["DName"]; ["Daddress"].Value = [i]["Daddress"]; ["Dtelphone"].Value = [i]["Dtelphone"]; } } //Set IsEx to true to indicate that the node has been expanded this.[].Cells["IsEx"].Value = "true"; this.[].Cells["EX"].Value = "-";
Delete child nodes:
if (this.[].Name == "EX" && isEx == "true") { string id = this.[].Cells["ID"].(); DataTable table = GetDataTable("select * from Department where DparentId=" + id); if ( > 0) { //Use Remove for (int i = 0; i < ; i++) { foreach (DataGridViewRow row in this.) { if (["ID"].([i]["ID"])) { this.(row); } } } } //// Set IsEx to false to indicate that the node has contracted this.[].Cells["IsEx"].Value = "false"; this.[].Cells["EX"].Value = "+"; }
Here, by comparing the ID, a row is uniquely determined, and there are many loops. Because the child node is immediately followed by the parent node, we can determine the number of rows where the child node is located, so it is better to use the RemoveAt() method.
//Use RemoveAt for (int i = ; i > 0; i--) { //Delete the line this.(i + ); }
The above approach is achieved through continuous insertion and deletion, but the interaction with the database becomes very frequent. A better approach would be to insert it once and then achieve our effect by hiding or showing the lines.
To do this, we need to add two new columns to the grid:
IsInsert: used to determine whether the row has inserted child node data
RowCount: Used to save the number of child nodes inserted under this row.
In the method DataGridBing, when binding data, another column should be added:
//Whether to insert["IsInsert"].Value = "false";
When adding nodes, we need to make an extra judgment. If IsInsert is false, insert data, and if true, display data
Expand the line
if (this.[].Name == "EX" && isEx=="false") { if (this.[].Cells["IsInsert"].() == "false") { string id = this.[].Cells["ID"].(); DataTable table = GetDataTable("select * from Department where DparentId=" + id); if ( > 0) { //Insert row this.( + 1, ); for (int i = 0; i < ; i++) { DataGridViewRow row = this.[ + i + 1]; = ; ["ID"].Value = [i]["ID"]; ["DName"].Value = [i]["DName"]; ["Daddress"].Value = [i]["Daddress"]; ["Dtelphone"].Value = [i]["Dtelphone"]; } this.[].Cells["IsInsert"].Value = "true"; this.[].Cells["RowCount"].Value = ; } } else { //Display data int RowCount = Convert.ToInt32(this.[].Cells["RowCount"].Value); for (int i = 1; i <= RowCount; i++) { this.[ + i].Visible = true; } } //Set IsEx to true to indicate that the node has been expanded this.[].Cells["IsEx"].Value = "true"; this.[].Cells["EX"].Value = "-"; }
When shrinking, we just need to hide the way.
Contraction row
if (this.[].Name == "EX" && isEx == "true") { int RowCount = Convert.ToInt32(this.[].Cells["RowCount"].Value); for (int i = 1; i <= RowCount; i++) { //Hide the line this.[ + i].Visible = false; } //// Set IsEx to false to indicate that the node has contracted this.[].Cells["IsEx"].Value = "false"; this.[].Cells["EX"].Value = "+"; }