我想知道是否可以将 Excel 输出设置为“锁定”,因为当我们尝试更改单元格的值时,会出现警告,表明我们无法更改它,除非我们删除表的保护。
我知道我们可以开发自定义 Excel 自动化代码,并在保存工作表之前设置密码来保护工作表。但是,有没有什么简单的方法可以使用 ReportViewer 的内置功能来实现这一点?
我想知道是否可以将 Excel 输出设置为“锁定”,因为当我们尝试更改单元格的值时,会出现警告,表明我们无法更改它,除非我们删除表的保护。
我知道我们可以开发自定义 Excel 自动化代码,并在保存工作表之前设置密码来保护工作表。但是,有没有什么简单的方法可以使用 ReportViewer 的内置功能来实现这一点?
经过一番研究,我设法找到了解决方案:)想法是拦截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 手动编写报告代码(设置边框、合并单元格、分组)会很麻烦。