Export to Excel using ReportViewer built-in feature

断了今生、忘了曾经 提交于 2019-12-07 08:58:47

问题


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.

I know that we can develop a custom Excel automation code, and set a Password to protect the sheet just before we save it. But, is there any easy way to accomplish this using ReportViewer's built-in feature?


回答1:


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. 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. 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.

For those using WinForm, you can override the ReportExport event like this :

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. 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. I decided to render the excel file directly. 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. The output format is in byte[], and I use FileStream to write it. After it is done, I open the Excel file using Interop and apply protection. 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. Imagine the hassle if we manually code the report using Excel (setting borders, merge cells, groupings).



来源:https://stackoverflow.com/questions/12241736/export-to-excel-using-reportviewer-built-in-feature

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!