ITPub博客

首页 > IT职业 > IT图书 > FineUI多表头表格导出小技巧

FineUI多表头表格导出小技巧

IT图书 作者:supergirlxu 时间:2021-09-09 09:14:15 0 删除 编辑
id="article_content">

在 ASPX 中,我们通过 GroupField 列来定义多表头,如下所示:


    
        
            
                
            
        
        
            
                
                
                    
                        
                    
                
                
                    
                        
                        
                        
                    
                
            
        
        
        
    

这是一个树状的结构,通过 GroupField 的 Columns 集合来定义子列,从而实现多表头的效果:

图片描述  

 

老方法已经不再奏效

如果照搬之前的逻辑,我们和容易写出如下的导出代码(处理数组很简单,循环搞定):

protected void Button1_Click(object sender, EventArgs e)
{
    Response.ClearContent();
    Response.AddHeader("content-disposition", "attachment; filename=myexcel.xls");
    Response.ContentType = "application/excel";
    Response.ContentEncoding = System.Text.Encoding.UTF8;
    Response.Write(GetGridTableHtml(Grid1));
    Response.End();
}
 
private string GetGridTableHtml(Grid grid)
{
    StringBuilder sb = new StringBuilder();
 
    sb.Append("");
 
 
    sb.Append("
");       sb.Append("");     foreach (GridColumn column in grid.Columns)     {         sb.AppendFormat("", column.HeaderText);     }     sb.Append("");         foreach (GridRow row in grid.Rows)     {         sb.Append("");           foreach (GridColumn column in grid.Columns)         {             string html = row.Values[column.ColumnIndex].ToString();               if (column.ColumnID == "tfNumber")             {                 html = (row.FindControl("spanNumber") as System.Web.UI.HtmlControls.HtmlGenericControl).InnerText;             }             else if (column.ColumnID == "tfGender")             {                 html = (row.FindControl("labGender") as AspNet.Label).Text;             }                 sb.AppendFormat("", html);         }           sb.Append("");     }       sb.Append("
{0}
{0}
");       return sb.ToString(); }

打开导出的文件,我们会发现所有子列都不见了:

图片描述  

这样很容易理解,因为在后台,FineUI 也是按照树状的结构存储 Grid1.Columns 属性的:

[{
    "text": "分组一",
    "columns": [{
        "text": "姓名"
    }, {
        "text": "性别"
    }, {
        "text": "考试成绩",
        "columns": [{
            "text": "语文成绩"
        }, {
            "text": "数学成绩"
        }, {
            "text": "总成绩"
        }]
    }, ]
}, {
    "text": "所学专业"
}, {
    "text": "注册日期"
}]

  

树状结构转换为 table 标签

这个还真不好办,因为 table 标签不像它看起来那么简单,每个单元格都可能要设置 rowspan 和 colspan,来看下我们最终需要的结构:

图片描述

最终生成的 table 标签如下所示:



    
        
        
        
        
    
    
        
        
        
    
    
        
        
        
    
分组一所学专业注册日期
姓名性别考试成绩
语文成绩数学成绩总成绩

最终生成了 3 行数据,每一行中 th 的个数不尽相同,每个 th 的参数也不相同,看来这个转换要自己手工做了。

 

实现转换之前,我们先来总结两个关键的逻辑:

1. 如果某列有子列,则更改本列的 colspan,并且增加所有父列(向上追溯)的 colspan

2. 如果下一行有数据,则增加上一行(向上追溯)中没有子项的列的 rowspan

 

每个 th 在 C# 代码中通过 object[] 来表达,比如 [考试成绩] 这一列最终的结构是:

[
    1,          // rowspan
    3,          // colspan
    考试成绩,           // 当前列对象
    分组一     // 父列对象
]

 

逻辑点到为止,剩下的就来看代码了,我们把逻辑封装到自定义类中:

public class MultiHeaderTable
{
    // 包含 rowspan,colspan 的多表头,方便生成 HTML 的 table 标签
    public List> MultiTable = new List>();
    // 最终渲染的列数组
    public List Columns = new List();
 
 
    public void ResolveMultiHeaderTable(GridColumnCollection columns)
    {
        List row = new List();
        foreach (GridColumn column in columns)
        {
            object[] cell = new object[4];
            cell[0] = 1;    // rowspan
            cell[1] = 1;    // colspan
            cell[2] = column;
            cell[3] = null;
 
            row.Add(cell);
        }
 
        ResolveMultiTable(row, 0);
 
        ResolveColumns(row);
    }
 
    private void ResolveColumns(List row)
    {
        foreach (object[] cell in row)
        {
            GroupField groupField = cell[2] as GroupField;
            if (groupField != null && groupField.Columns.Count > 0)
            {
                List subrow = new List();
                foreach (GridColumn column in groupField.Columns)
                {
                    subrow.Add(new object[]
                    {
                        1,
                        1,
                        column,
                        groupField
                    });
                }
 
                ResolveColumns(subrow);
            }
            else
            {
                Columns.Add(cell[2] as GridColumn);
            }
        }
 
    }
 
    private void ResolveMultiTable(List row, int level)
    {
        List nextrow = new List();
 
        foreach (object[] cell in row)
        {
            GroupField groupField = cell[2] as GroupField;
            if (groupField != null && groupField.Columns.Count > 0)
            {
                // 如果当前列包含子列,则更改当前列的 colspan,以及增加父列(向上递归)的colspan
                cell[1] = Convert.ToInt32(groupField.Columns.Count);
                PlusColspan(level - 1, cell[3] as GridColumn,groupField.Columns.Count - 1);
 
                foreach (GridColumn column in groupField.Columns)
                {
                    nextrow.Add(new object[]
                    {
                        1,
                        1,
                        column,
                        groupField
                    });
                }
            }
        }
 
        MultiTable.Add(row);
 
        // 如果当前下一行,则增加上一行(向上递归)中没有子列的列的 rowspan
        if (nextrow.Count > 0)
        {
            PlusRowspan(level);
 
            ResolveMultiTable(nextrow, level + 1);
        }
    }
 
    private void PlusRowspan(int level)
    {
        if (level  0)
            {
                // ...
            }
            else
            {
                cells[0] = Convert.ToInt32(cells[0]) + 1;
            }
        }
 
        PlusRowspan(level - 1);
    }
 
    private void PlusColspan(int level, GridColumn parent, int plusCount)
    {
        if (level 

 

其实主要的逻辑就上面提到的两点,然后需要好几个递归函数来一块完成任务。

 

导出的代码调用如下:

protected void Button1_Click(object sender, EventArgs e)
{
    Response.ClearContent();
    Response.AddHeader("content-disposition", "attachment; filename=myexcel.xls");
    Response.ContentType = "application/excel";
    Response.ContentEncoding = System.Text.Encoding.UTF8;
    Response.Write(GetGridTableHtml(Grid1));
    Response.End();
}
 
private string GetGridTableHtml(Grid grid)
{
    StringBuilder sb = new StringBuilder();
 
    MultiHeaderTable mht = new MultiHeaderTable();
    mht.ResolveMultiHeaderTable(Grid1.Columns);
 
 
    sb.Append("");
 
 
    sb.Append("
");       foreach (List rows in mht.MultiTable)     {         sb.Append("");         foreach (object[] cell in rows)         {             int rowspan = Convert.ToInt32(cell[0]);             int colspan = Convert.ToInt32(cell[1]);             GridColumn column = cell[2] as GridColumn;               sb.AppendFormat("",                 rowspan != 1 ? " rowspan="" + rowspan + """ : "",                 colspan != 1 ? " colspan="" + colspan + """ : "",                 colspan != 1 ? " style="text-align:center;"" : "",                 column.HeaderText);         }         sb.Append("");     }         foreach (GridRow row in grid.Rows)     {         sb.Append("");           foreach (GridColumn column in mht.Columns)         {             string html = row.Values[column.ColumnIndex].ToString();               if (column.ColumnID == "tfNumber")             {                 html = (row.FindControl("spanNumber") as System.Web.UI.HtmlControls.HtmlGenericControl).InnerText;             }             else if (column.ColumnID == "tfGender")             {                 html = (row.FindControl("labGender") as AspNet.Label).Text;             }                 sb.AppendFormat("", html);         }           sb.Append("");     }       sb.Append("
{3}
{0}
");       return sb.ToString(); }

最终导出的文件结构如下所示:

图片描述

 

原创不易,请点赞

短短一篇文章,几行代码,看似轻描淡写,实则是花了很大功夫调试。你觉得作者在整个过程中做了多少次导出文件的动作?才最终实现了这个效果! 

。

。

10?

。

。

。

20?

。

。

。

。

30?

。

。

。

。

。

。

40?

。

。

。

。

。

。

。

请恕作者愚钝,足足不下 50 次:

图片描述

 

本章小结

本篇文章介绍了如何导出多表头表格,重点在于树状结构到 table 标签结构的转换,虽然实现稍微复杂了点,但只要思路清晰,最终还是能否完整呈现的。

 

来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/644/viewspace-2800928/ ,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论

注册时间:2019-04-12

  • 博文量
    220
  • 访问量
    1690