带列设计器的 Excel 生成器






4.56/5 (25投票s)
一个完全可定制和可扩展的 C# 库,可以轻松地为给定的 DataSet 生成 Excel 文件,并支持列布局设计。
引言
这是一个完全可定制和可扩展的 C# 库,使用 .NET Framework 3.5,可以通过传递 ADO.NET DataView 对象轻松创建 Excel 文件。 在某些情况下,您可能需要在不使用 MS Office 组件的情况下生成 MS Excel 格式的报表。 这种场景在许多项目的生产环境中很常见。
此外,此库将允许您自由地为给定的 DataSet 设计自己的列布局。 列布局设计器是一个 WinForms 应用程序。 具有导出功能的核心库可以在 WinForms 和 ASP.NET Web 应用程序中使用。 在运行时,如果它找不到给定报表的任何布局信息,它将导出所有列的数据。
类图

使用代码
- 打开 Visual Studio 2008 IDE 并创建一个名为“SpreadsheetDemo”的 C# Windows 应用程序项目。
- 将 Form1重命名为TestReport。
- 添加对库的引用。
- 将以下控件粘贴到 TestReport窗体中
- 在窗体的声明部分添加以下行
| 类型 | 名称 | 标题 | 
| Label | lable1 | 国家 | 
| ComboBox | comboCountry | |
| Button | btnGo | GO | 
| DataGridView | DataGridView1 | |
| Label | lblStatus | 状态 | 
| Button | btnDesign | 设计 | 
| Button | btnGenerateExcel | 导出到 Excel | 
| Button | btnCancel | 取消 | 
该窗体应在 Visual Studio 设计视图中看起来像下面的屏幕

// variables
private Spreadsheet spreadsheet  = null;
private string reportId = string.Empty;
private string reportTitle = string.Empty;
private string reportConfigFile =  string.Empty;
private string outputFile = string.Empty;
TestReport_Load 事件中添加以下行// load the country data into combo box
private void TestReport_Load(object sender, System.EventArgs e)
{
    PrepareDataset();
    spreadsheet = new Spreadsheet();
    spreadsheet.OnProgress+= 
      new sommon.Spreadsheet.Spreadsheet.StatusHandler(xmlSheet_OnProgress);
    spreadsheet.OnError+=
      new sommon.Spreadsheet.Spreadsheet.StatusHandler(xmlSheet_OnError);
    spreadsheet.OnFinish+=
      new sommon.Spreadsheet.Spreadsheet.StatusHandler(xmlSheet_OnFinish);
}
private void  PrepareDataset()
{
    if(!File.Exists("Customers.xml"))
    {
        MessageBox.Show("Cannot find the Customers.xml file.", 
                        this.Text, MessageBoxButtons.OK, 
                        MessageBoxIcon.Exclamation );
        this.Close();
        return;
    }
    // prepare the dataset 
    reportDataSet.ReadXml("Customers.xml");
    reportDataSet.Tables[0].TableName = "Customers";
    reportDataSet.Tables[1].TableName = "Country";
    // set the combo box for country selection
    comboCountry.DataSource = reportDataSet.Tables["Country"].DefaultView;
    comboCountry.DisplayMember = "Country";
    comboCountry.ValueMember = "Country";
}
Click 事件中添加以下行private void btnGo_Click(object sender, EventArgs e)
{
   // Prepare dataset and bind the datasource to grid
    InitializeReportData();
}
private void InitializeReportData()
{
    // here you can build the dataset as per your requirement.
    // In this example we will simply filter the existing dataset
    // based on the country selection.
    DataView reportView = null;
    string country = comboCountry.Text;
    lblStatus.Text = "";
    if (country == "All")
         reportView = reportDataSet.Tables["Customers"].DefaultView;
    else
    {
        string rowFilter = "Country = '" + country + "'";
                           lblStatus.Text = "Filter: " +  rowFilter; 
        reportView = new DataView(reportDataSet.Tables["Customers"], 
             rowFilter,"CompanyName", DataViewRowState.CurrentRows);
    }
    // assign reportView object to spreadsheet class
    spreadsheet.DataView = reportView;
    // bind the datasource into data grid
    dataGridView1.DataSource = reportView;
}
Click 事件中添加以下行private void btnGenerateExcel_Click(object sender, System.EventArgs e)
{
    if(!ValidateAll())
    return;
    EnableButton(false);
    GenerateReport(OutputType.Excel);
    EnableButton(true);
}
private void EnableButton(bool enable)
{
    btnDesign.Enabled = enable;
    btnGenerateExcel.Enabled = enable;
    btnGenerateHtml.Enabled = enable;
}
private void GenerateReport(OutputType outputType)
{
    reportId = "CustomerList";
    reportTitle = "List of Customer";
    reportConfigFile =  "Report.config";
    outputFile = Application.StartupPath + @"\"+ reportTitle;
    try
    {
        this.Cursor = Cursors.WaitCursor;
        // setting output file
        spreadsheet.ExportFile = outputFile;
        // Initialize the ColumnStyles item
        spreadsheet.InitializeReportColumns(reportConfigFile,reportId);
        // initialize the report data based on specified search criteria 
        InitializeReportData();
        if(spreadsheet.DataView.Count==0)
        {
            this.Cursor = Cursors.Default;
            MessageBox.Show("No Records Found.", 
              this.Text,MessageBoxButtons.OK, 
              MessageBoxIcon.Information,MessageBoxDefaultButton.Button1); 
            return;
        }
        spreadsheet.GenerateWorkSheet(outputType);
        this.Cursor = Cursors.Default;
    }
    catch(Exception ex)
    {
        this.Cursor = Cursors.Default;
        MessageBox.Show("Unable to generate report.\n"+ 
          ex.Message,this.Text,MessageBoxButtons.OK, 
          MessageBoxIcon.Error,MessageBoxDefaultButton.Button1); 
    }
}
private bool ValidateAll()
{
    // for a demo purpose I have hard coded the return value 
    // as true but you can implement your own logic here.
    return true;
}
Click 事件private void btnDesign_Click(object sender, System.EventArgs e)
{
    reportId = "CustomerList";
    reportTitle = "List of Customer";
    reportConfigFile =  "Report.config";
    spreadsheet.InitializeReportColumns(reportConfigFile,reportId);
    // Prepare dataset
    InitializeReportData();
    ReportDesigner frm = 
       new ReportDesigner(reportConfigFile, reportId,spreadsheet);
    frm.ShowDialog();
}
示例客户报表输入屏幕

如何打开列布局设计器窗口
string reportId = "CustomerList";
string reportTitle = "List of Customer";
string reportConfigFile =  "Report.config";
Spreadsheet spreadsheet  = new Spreadsheet();
// Initialize the ColumnStyles item
spreadsheet.InitializeReportColumns(reportConfigFile,reportId);
// initialize the report data based on specified search criteria 
InitializeReportData();
// create instance of ReportDesigner class
ReportDesigner frm = new ReportDesigner(reportConfigFile, reportId,spreadsheet);
// show the designer window
frm.ShowDialog();
客户报表的列设计器屏幕

如何调用导出到 Excel 任务
reportId = "CustomerList";
reportTitle = "List of Customer";
reportConfigFile =  "Report.config";
outputFile = Application.StartupPath + @"\"+ reportTitle;
try
{
    this.Cursor = Cursors.WaitCursor;
    // setting output file
    spreadsheet.ExportFile = outputFile;
    // Initialize the ColumnStyles item
    spreadsheet.InitializeReportColumns(reportConfigFile,reportId);
    // initialize the report data based on specified search criteria 
    InitializeReportData();
    if(spreadsheet.DataView.Count==0)
    {
        this.Cursor = Cursors.Default;
        MessageBox.Show("No Records Found.", 
          this.Text,MessageBoxButtons.OK,MessageBoxIcon.Information,
          MessageBoxDefaultButton.Button1); 
        return;
    }
    spreadsheet.GenerateWorkSheet(outputType);
    this.Cursor = Cursors.Default;
}
catch(Exception ex)
{
    this.Cursor = Cursors.Default;
    MessageBox.Show("Unable to generate report.\n"+ ex.Message, 
      this.Text,MessageBoxButtons.OK,MessageBoxIcon.Error, 
      MessageBoxDefaultButton.Button1);
}
客户报表 (Excel)

Excel 生成器的工作原理
基本上,它创建一个 XML 电子表格文件作为输出。 GenerateWorkSheet 方法负责创建输出文件。 生成输出文件时遵循以下步骤
- 声明一个 StringBuilder类型的变量并将以下结果添加到其中
- 创建一个 Excel 标头字符串
- 创建所有样式字符串
- 创建一个工作表选项字符串(仅需要一次)
- 创建第一个工作表标签字符串
- 创建表标签
- 创建表标题样式标签
- 循环遍历 DataView并为每一行、每一列创建一个 Excel 兼容标签
- 关闭 Workbook 标签
- 将字符串保存在输出文件中。
- 通知调用者有关状态。
结论
使用上面的库,您可以在几分钟内轻松生成 Excel 文件,从而提高您的效率和生产力。 此库使您可以从 MS Office Primary Interop Assemblies (PIA) 中解放出来,这些程序集体积庞大、内存消耗高且依赖于系统。


