セルの値を変更しようとすると、セルを削除しない限り変更できないことを示す警告が表示されるという意味で、Excel 出力を「ロック」として設定できるかどうかを知りたいです。シートの保護。
カスタム Excel オートメーション コードを開発し、シートを保存する直前にパスワードを設定してシートを保護できることはわかっています。しかし、ReportViewer の組み込み機能を使用してこれを実現する簡単な方法はありますか?
セルの値を変更しようとすると、セルを削除しない限り変更できないことを示す警告が表示されるという意味で、Excel 出力を「ロック」として設定できるかどうかを知りたいです。シートの保護。
カスタム Excel オートメーション コードを開発し、シートを保存する直前にパスワードを設定してシートを保護できることはわかっています。しかし、ReportViewer の組み込み機能を使用してこれを実現する簡単な方法はありますか?
いくつかの調査を行った後、解決策を見つけることができました :) アイデアは、ReportViewer のレポートのエクスポート機能をインターセプトし、独自のプロセスを実行することです。このプロセスは、生成される Excel ファイルである出力を取得し、それを読み取って必要な変更を適用し、ダウンロードとしてユーザーに送信する前に再度保存します。ただし、傍受方法は、使用するレポートの種類によって異なることに注意してください。私の場合、ReportViewer は WinForm の代わりに WebForm を使用しています。ほとんどの説明は、WinForm でのみ利用可能な ReportExport イベントについて説明しています。
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 を使用して手動でレポートをコーディングする場合の手間を想像してみてください (境界線の設定、セルの結合、グループ化)。