Windows Forms C# 中的嵌套 DataGridView






4.78/5 (48投票s)
适用于 Winforms 的嵌套或主从或分层 DataGridView
引言
在我上一篇文章中,我解释了如何使用 C# 创建一个 DataGridView
辅助类。
我扩展了 DataGridView
辅助类来创建一个嵌套的 DataGridView
。几天前,一位 CodeProject 会员询问如何在 WinForms 中创建嵌套的或主从详情或分层 DataGridView
。我开始在 Google 上搜索,但没有找到任何关于嵌套 DataGridView
的结果。我开始着手创建一个嵌套 DataGridView
的示例程序,这应该对所有人都有用。因此,我创建了一个嵌套 DataGridView
,您可以在本文开头提供的链接中找到源代码。我的目标是为用户创建一个简单易懂的程序。用户可以下载代码并根据自己的需求进行定制。
为什么我们需要嵌套或分层 DataGridView
在实际项目中,例如订单管理、生产管理等,我们需要以分层结构显示数据。
例如,让我们以一家餐厅的订单管理项目为例。假设有四个人去餐厅吃午餐。餐厅的服务员会给他们菜单卡,让他们选择要点的菜品。现在,在一张桌子旁,总共有四个人坐着。在餐厅管理中,通常所有桌子都会有一个唯一的桌子 ID 或名称。这四个人将从菜单卡中选择他们需要的菜品,并下单,以便为他们提供食物。在餐厅管理中,对于每个订单,我们将在订单主表中创建一个唯一的 ID,并在订单详情表中存储与该订单相关的所有项目详情。让我们看一个订单的示例结构。
为什么我们需要主表和详情表?
为了避免数据重复,我们可以使用主从详情表关系来存储数据。例如,每个订单会有一个服务员和一张桌子,所以如果我们不使用主从详情表关系,结果将如下所示:
在这里,我们可以看到订单号、桌子 ID、服务员姓名和订单日期被重复了。为了避免这些重复数据,我们将创建主表和详情表关系。请参阅下面的主表和详情表。
订单主表
在这里,我们可以看到重复的数据已存储在名为订单主表的单独表中。
订单详情表
在这里,我们可以看到订单的所有项目详情都在一个单独的表中。但是,在详情表中,我们使用了 Order NO
来与 Master
表建立关联。通过这种关联,我们可以合并这两个表并生成输出。
普通网格结果
结果可以显示而不使用分层网格输出。但我们必须如下所示显示重复的结果:
我们也可以合并相同的数据并如下表所示显示结果。但输出效果不太好,也不易于查看和理解。
现在让我们看看相同结果的分层输出。
现在这个最终结果看起来比之前所有都好多了。可以轻松查看所有记录的主表和详情。
这是我的分层 DataGridView
的示例输出。
与餐厅项目中的订单管理类似,我们将有账单主表和详情表、账户主表和详情表、商品主表和详情表、库存主表和详情表。在生产项目中,我们将有生产订单主表和订单详情表、成品入库主表和详情表、成品出库主表和详情表等。与此类似,在我们所有的实际项目中,我们将使用主从详情关系来显示我们的数据。
Using the Code
正如我所说,在这篇文章中,我使用并扩展了我的 DataGridView
辅助类来创建一个嵌套 DataGridView
。您可以通过我的文章查看我的 DataGridView
辅助类的详细信息。
在我的 DGVhelper
类中,我添加了以下功能来创建嵌套网格:
ImageCoulmn (图片列)
DGVMasterGridClickEvents (主网格点击事件)
DGVDetailGridClickEvents (详情网格点击事件)
用户可以对主网格和详情网格使用所有事件,例如 CellClick
、CellContentClick
等。
我创建了两个单独的列表类来填充主表和详情结果。在窗体加载时,调用方法将详情添加到每个列表类中。
我使用我的 ShanuDGVHelper
类以编程方式(动态地)创建了主表和详情 DataGridView
。
主网格设置
在窗体加载时,我调用了此方法在运行时创建主 DataGridView
。
在我的代码中,我在每行之前添加了注释来解释其用途。
// 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;
}
单元格点击事件
我调用了上面的方法来为主 DataGridView
创建一个单元格点击事件。
// 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");
此事件将用于主网格图片点击事件。在此事件中,我将获取订单号并从 DataTabledetail
中过滤结果。将最终的 Dataview
结果显示到 Detail DataGridView
。
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;
}
}
在单元格点击事件中,如果点击了图片列,我将根据选定的图片名称将图片更改为 Expand
(展开)和 Collapse
(折叠)。
如果选择图片进行 Expand
(展开),那么我将使详情 DataGridView
可见。
在单元格点击事件中,我将获取当前选定的订单号。此订单号将用于“DataView
”以仅过滤选定的订单结果。最终结果将绑定到 Detail DataGridView
。
详情网格设置
在窗体加载时,我调用了此方法在运行时创建 Detail DataGridView
。
在我的代码中,我在每行之前添加了注释来解释其用途。
// 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 DataGridView
创建一个单元格点击事件。
objshanudgvHelper.DGVDetailGridClickEvents(Detail_shanuDGV);
此事件将用于详情网格单元格点击事件。在详情网格的单元格点击时,我将获取每个单元格的文本并显示在 Messagebox
中。
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);
}
}
关注点
此程序解释了创建单级分层 DataGridView
的基本功能。此功能可用于创建多级分层 DataGridView
。
历史
- 2014 年 12 月 2 日:版本 1.0