简体   繁体   English

使用ReportViewer内置功能导出到Excel

[英]Export to Excel using ReportViewer built-in feature

I'd like to know if it is possible to set the Excel output as "Locked", in the sense that when we try to change a Cell's value, then there will be a warning indicating that we can not change it unless we remove the Sheet's protection. 我想知道是否可以将Excel输出设置为“已锁定”,这是因为当我们尝试更改Cell的值时,会有一个警告,指示我们无法更改它,除非我们删除表的保护。

I know that we can develop a custom Excel automation code, and set a Password to protect the sheet just before we save it. 我知道我们可以开发自定义Excel自动化代码,并设置密码以在保存之前保护工作表。 But, is there any easy way to accomplish this using ReportViewer's built-in feature? 但是,使用ReportViewer的内置功能有没有简单的方法来实现这一目标?

After doing some research, I've managed to find the solution :) The idea is to intercept the Export Report function of ReportViewer, and then run our own process. 在做了一些研究后,我设法找到了解决方案:)这个想法是拦截ReportViewer的Export Report功能,然后运行我们自己的进程。 This process will get output which is the Excel file being generated, and then read it and apply whatever changes necessary, and save it again before it is sent as a Download to User. 此过程将获得输出,即生成的Excel文件,然后读取并应用所需的任何更改,并在将其作为“下载到用户”发送之前再次保存。 It should be noted however, that the interception method will be different based on what type of Reporting that we use. 但应注意,拦截方法将根据我们使用的报告类型而有所不同。 In my case, my ReportViewer is using WebForm instead of WinForm, and most explanation out there is explaining about ReportExport event which is only available in WinForm. 在我的例子中,我的ReportViewer使用WebForm而不是WinForm,并且大多数解释都解释了ReportExport事件,该事件仅在WinForm中可用。

For those using WinForm, you can override the ReportExport event like this : 对于那些使用WinForm的人,您可以像这样覆盖ReportExport事件:

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

In WebForm, there is no event handler of ReportExport. 在WebForm中,没有ReportExport的事件处理程序。 The options that I can think of are creating a custom button in .aspx that will execute our custom code, or directly render the excel without needing to preview the report. 我能想到的选项是在.aspx中创建一个自定义按钮来执行我们的自定义代码,或直接渲染excel而无需预览报告。 I decided to render the excel file directly. 我决定直接渲染excel文件。 I will use a dataset and get the data from Stored Procedure. 我将使用数据集并从存储过程中获取数据。 Then, I assign the dataset into RDLC and call the Render method to get the output. 然后,我将数据集分配到RDLC并调用Render方法来获取输出。 The output format is in byte[], and I use FileStream to write it. 输出格式是byte [],我使用FileStream来编写它。 After it is done, I open the Excel file using Interop and apply protection. 完成后,我使用Interop打开Excel文件并应用保护。 Here is the code : 这是代码:

// 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);

}

By using this concept, I can easily design the report output since I'm using RDLC as a template to populate the data supplied by SP, and then render it. 通过使用这个概念,我可以轻松地设计报表输出,因为我使用RDLC作为模板来填充SP提供的数据,然后渲染它。 Imagine the hassle if we manually code the report using Excel (setting borders, merge cells, groupings). 想象一下,如果我们使用Excel手动编写报告(设置边框,合并单元格,分组),则会很麻烦。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM