ASP.NET 中动态的多行多列网格标题






4.47/5 (12投票s)
在 ASP.NET 中为 DataGrid 或 GridView 创建具有多行/列的动态标题。
引言
让我们假设我们有一个如下所示的产品表
ProductId | ProductName | ParentProductId(父产品ID) |
1 | SOAP | NULL |
2 | SHAMPOO(洗发水) | NULL |
3 | Bath Soap(沐浴皂) | 1 |
4 | Pink Soap(粉色香皂) | 3 |
5 | White Soap(白色香皂) | 3 |
6 | Toilet Soap(卫生香皂) | 1 |
如您所见,标题的深度是 3。此深度可以是任何数字,即,对层次结构深度没有限制。我们的目标是在 GridView
或 DataGrid
的顶部添加一个标题,如下所示
SOAP | SHAMPOO(洗发水) | ||
Bath Soap(沐浴皂) | Toilet Soap(卫生香皂) | ||
White Soap(白色香皂) | Pink Soap(粉色香皂) |
背景
我采用的方法是在 DataGrid
/GridView
的标题中绘制具有适当行和列跨度的表格单元格。因此,问题可以简化为如何创建具有适当行和列跨度的表格单元格集合以获得所需效果。
- 步骤 1:我们需要创建一个标题字符串,例如 SOAP|Bath Soap|Pink Soap,SOAP|Bath Soap|White Soap,SOAP|Toilet Soap,SHAMPOO。如果我们仔细观察字符串,我们会发现每个产品都以 '|'(管道符)分隔的字符串的形式创建,其中包含其所有父项。然后,所有这些产品字符串都使用 ',' 作为分隔符连接成一个标题字符串。在本文中,字符串是硬编码的。但在实际开发中,字符串可以从数据库中使用存储过程形成。
- 步骤 2:我们将检查每个产品字符串并找出 '|' 的最大出现次数。该数字加 1(比如 M)将是标题的行数。在本例中,M=3。找出列数(比如 N)很简单。它将是产品字符串的数量,在本例中,N=4。
- 步骤 3:我们将创建一个 M × N 矩阵并将标题字符串放置如下
- 步骤 4:我们将比较每一行的两个相邻单元格的内容。如果内容相同,我们将第一个单元格的列跨度增加 1 并删除第二个单元格的内容。然后,我们将比较每一列的两个相邻单元格的内容。如果 cell1 有值而 cell2 没有任何值,我们将第一个单元格的行跨度增加 1。对于每一行,我们将创建一个带有已计算的列和行跨度的标题集合。在本例中,将有三个这样的集合。然后,我们将这些集合放入一个容器集合中进行渲染。
- 最后一步 (步骤 5):我们将渲染带有行和列跨度的表格单元格以实现我们的目标。在渲染时,我们可以控制表格单元格的属性以获得更好的外观和感觉。在本例中,我为不同级别的标题使用了不同的背景颜色和字体大小。我还添加了一个包含一些数据(例如产品的销售数据)的 XML 文件,最终结果是
SOAP | SOAP | SOAP | SHAMPOO(洗发水) |
Bath Soap(沐浴皂) | Bath Soap(沐浴皂) | Toilet Soap(卫生香皂) | |
White Soap(白色香皂) | Pink Soap(粉色香皂) |
SOAP | SHAMPOO(洗发水) | ||
Bath Soap(沐浴皂) | Toilet Soap(卫生香皂) | ||
Pink Soap(粉色香皂) | White Soap(白色香皂) | ||
100 | 200 | 300 | 400 |
10 | 20 | 30 | 40 |
1 | 2 | 3 | 4 |
100 | 200 | 300 | 400 |
使用代码
我创建了三个类来解析标题字符串并创建集合以进行渲染
DynamicHeaderCell (动态标题单元格)
DynamicHeader (动态标题)
DynamicHeaders (动态标题集合)
DynamicHeaderCell (动态标题单元格)
public class DynamicHeaderCell
{
public String Header { get; set; }
public int RowSpan { get; set; }
public int ColSpan { get; set; }
public DynamicHeaderCell(String header)
{
RowSpan = 1;
ColSpan = 1;
Header = header;
}
}
此类的对象用于生成集合。标题字符串将是 TableCell
的内容,而 RowSpan
和 ColSpan
将用于设置表格单元格的 RowSpan
和 ColumnSpan
。
DynamicHeader (动态标题)
public class DynamicHeader
{
public int HeaderDepth { get; set; }
public String[] Headers { get; set; }
public DynamicHeader(String header)
{
Headers = header.Split('|');
HeaderDepth = Headers.Length;
}
}
每个单独的产品字符串都在此类中解析。深度存储在 HeaderDepth
中。
DynamicHeaders (动态标题集合)
public class DynamicHeaders
{
List<DynamicHeader> Headers;
int HeaderRows;
int HeaderCols;
public DynamicHeaders(String Header)
{
Headers = new List<DynamicHeader>();
String[] HeaderParts = Header.Split(',');
foreach (String tmpHeaderPart in HeaderParts)
Headers.Add(new DynamicHeader(tmpHeaderPart));
HeaderCols = Headers.Count;
HeaderRows = Headers.Max(H => H.HeaderDepth);
ParseHeader();
}
public ArrayList ParseHeader()
}
标题字符串在此类中解析。ParseHeader()
方法实现了上述逻辑并返回用于渲染的集合。
渲染
protected void GridViewWithDynamicHeader_RowCreated(object sender, GridViewRowEventArgs e)
{
if(e.Row.RowType == DataControlRowType.Header)
//Render the header
e.Row.SetRenderMethodDelegate(new RenderMethod(RenderHeader));
}
在 GridView
的 RowCreated
方法中,标题渲染已委托给 RenderHeader
方法。在 RenderHeader
方法中,调用 DynamicHeaders
类的 ParseHeader
方法,并从接收到的集合中渲染 TableCell
。