使用ReportViewer内置功能导出到Excel

时间:2012-09-03 03:44:37

标签: excel reportviewer

我想知道是否可以将Excel输出设置为“已锁定”,因为当我们尝试更改Cell的值时,会出现警告,指示我们无法更改它,除非我们删除了Sheet的保护。

我知道我们可以开发自定义Excel自动化代码,并设置密码以在保存之前保护工作表。但是,使用ReportViewer的内置功能有没有简单的方法来实现这一目标?

1 个答案:

答案 0 :(得分:8)

经过一些研究,我找到了解决办法:) 我们的想法是拦截ReportViewer的Export Report功能,然后运行我们自己的流程。此过程将获得输出,即生成的Excel文件,然后读取并应用所需的任何更改,并在将其作为“下载到用户”发送之前再次保存。 但应注意,拦截方法将根据我们使用的报告类型而有所不同。在我的例子中,我的ReportViewer使用WebForm而不是WinForm,并且大多数解释都解释了ReportExport事件,该事件仅在WinForm中可用。

对于那些使用WinForm的人,您可以覆盖ReportExport事件,如下所示:

void reportViewer_ReportExport(object sender, Microsoft.Reporting.WinForms.ReportExportEventArgs e)
{
    e.Cancel = true;
    // insert your own code to export excel
}

在WebForm中,没有ReportExport的事件处理程序。我能想到的选项是在.aspx中创建一个自定义按钮来执行我们的自定义代码,或直接渲染excel而无需预览报告。 我决定直接渲染excel文件。我将使用数据集并从存储过程中获取数据。然后,我将数据集分配到RDLC并调用Render方法来获取输出。输出格式是byte [],我使用FileStream来编写它。完成后,我使用Interop打开Excel文件并应用保护。这是代码:

// Setup DataSet (Adapter and Table)
YourTableAdapters.ATableAdapter ds = new YourTableAdapters.ATableAdapter();
YourDataSet.ADataTable dt = new YourDataSet.ADataTable ();

ds.Fill(dt, outlet, period);

// Create Report DataSource
ReportDataSource rds = new ReportDataSource("DataSet1", (System.Data.DataTable)dt);

// Variables needed for ReportViewer Render method
Warning[] warnings;
string[] streamIds;
string mimeType = string.Empty;
string encoding = string.Empty;
string extension = string.Empty;

// Setup the report viewer object and get the array of bytes
ReportViewer viewer = new ReportViewer();
viewer.ProcessingMode = ProcessingMode.Local;
viewer.LocalReport.ReportPath = "YourReport.rdlc";
viewer.LocalReport.DataSources.Add(rds); // Add datasource here

byte[] bytes = viewer.LocalReport.Render("Excel", null, out mimeType,
                                          out encoding, out extension,
                                          out streamIds, out warnings);

// Prepare filename and save_path, and then write the Excel using FileStream.
String temp_path = Path.Combine(Server.MapPath(Config.ReportPath), "FileName.xls");
FileStream fs = new FileStream(temp_path, FileMode.Create);
fs.Write(bytes, 0, bytes.Length);
fs.Close();

// Open the Excel file created, and add password protection.
PIDExcel pidexcel = new PIDExcel();
pidexcel.CollectExcelPID();

Microsoft.Office.Interop.Excel.Application xlApp = new Microsoft.Office.Interop.Excel.Application();
Microsoft.Office.Interop.Excel.Range lock_range = null;

int excelid = pidexcel.GetNewExcelID();

Microsoft.Office.Interop.Excel.Workbook xlWorkBook = null;

try
{
    //xlApp.Visible = true;
    xlWorkBook = (Microsoft.Office.Interop.Excel.Workbook)xlApp.Workbooks.Open(temp_path,
                  Type.Missing, Type.Missing, Type.Missing, Type.Missing,
                  Type.Missing, Type.Missing, Type.Missing, Type.Missing,
                  Type.Missing, Type.Missing, Type.Missing, Type.Missing,
                  Type.Missing, Type.Missing);

    foreach(Microsoft.Office.Interop.Excel.Worksheet displayWorksheet in xlApp.ActiveWorkbook.Worksheets)
    {
        lock_range = xlApp.Cells;
        lock_range.Select();
        lock_range.EntireColumn.Locked = true;
        displayWorksheet.Protect("<your password here>");
    }

}
catch (Exception ex)
{
    throw new Exception(ex.Message.Replace("'", "")); ;
}
finally
{
    // Set First Sheet Active
    xlWorkBook.Sheets[1].Select();
    xlApp.DisplayAlerts = false;
    xlWorkBook.Save();
    xlWorkBook.Close(Type.Missing, Type.Missing, Type.Missing);
    xlApp.Quit();

    System.Runtime.InteropServices.Marshal.FinalReleaseComObject(xlWorkBook);
    System.Runtime.InteropServices.Marshal.FinalReleaseComObject(xlApp);

    GC.WaitForPendingFinalizers();
    GC.Collect();

    pidexcel.KillExcel(excelid);

}

通过使用这个概念,我可以轻松地设计报告输出,因为我使用RDLC作为模板来填充SP提供的数据,然后渲染它。想象一下,如果我们使用Excel手动编写报告(设置边框,合并单元格,分组),那就麻烦了。