Page_Load イベント ハンドラでレポートをバインドする際の永続の制限
ASP.NET の Web アプリケーションでは、一般的な方法として、ページを起動するすべてのコードを Page_Load イベント ハンドラに設定しています。Page_Load イベント ハンドラは、Page.Load イベントによって呼び出されます。
特に、コントロールをデータ バインドするコードは、通常、Page_Load イベント ハンドラに記述されます。ただし、このイベント ハンドラにバインド コードを記述すると、ViewState に問題が発生します。この問題と一般的な解決策は次のとおりです。
- ViewState は、コントロールにバインドされたデータとコントロールで実行されるマウス クリック イベントの 2 つをページのリロードの間も維持するために使用されます。
- ViewState は文字列です。そのため、データとクリック イベントをシリアライズする必要があります。
- ページをリロードする際に、データとクリック イベントの両方が ViewState から復元されます。
- Page.Load イベントは、ViewState が復元された後に発生します。コントロールをバインドするコードが Page_Load イベント ハンドラに記述されていると、ページのリロードで、このバインド コードが ViewState を上書きして、元のデータとクリック イベントが失われます。
- この問題のよくある例として、ページのリロードによってコントロールがマウス クリック操作の情報を失う(DropDownList の選択など)場合があります。
- データとマウス クリック イベントを上書きしないようにするには、Page_Load イベント ハンドラ内のバインド コードをすべて Not IsPostBack 条件ブロックに記述します。これで、バインド コードがポストバックで呼び出されなくなります。
この解決法は、データとマウス クリック イベントをどちらも ViewState にシリアライズできるという重要な仮定を行っています。ただし、CrystalReportViewer コントロールは、シリアライズできないオブジェクト(具体的には ReportDocument クラス、ReportClientDocument クラス、InfoObject クラス)にバインドします。
注 |
---|
唯一の例外は、CrystalReportViewer コントロールがファイル ディレクトリ パスによってレポートにバインドされる場合、パス文字列が ViewState に永続するということです。このシナリオに限り、CrystalReportViewer コントロールは Not IsPostBack 条件ブロックに配置できます。ただし、このレポート バインド シナリオは上にリストされたレポート クラスにバインドするほど強力ではなく、あまり一般的には使用されません。 |
CrystalReportViewer コントロールのマウス クリック イベントだけを ViewState にシリアライズできるため、シリアライズできないレポート クラスにバインドすると、ページのリロードで解決できない問題が発生します。
- レポートをバインドするコードを Not IsPostBack 条件ブロックに記述すると、ViewState のマウス クリック イベントは保存されます。ただし、レポートのバインドは行われません。そのため、例外がスローされます。
- レポートをバインドするコードが条件ブロックの外に記述されると、レポートは正しくバインドされます。ただし、処理中に ViewState が上書きされます。そのため、マウス クリック イベントは失われます。
注 この状況は、CrystalReportViewer コントロールで複数のページを含むレポートをクリックする場合によく見られます。レポートはなぜか 1 ページ目を返し続けます。
推奨シナリオ:CrystalReportViewer コントロールのバインド コードを Init イベントに移動する
CrystalReportViewer コントロールの完全なソリューションは、ViewState の復元前に発生する Init イベントに、レポートをバインドするコードを移動することです。
このソリューションには、1 つ面倒な点があります。通常、Init イベントは、Load イベントほど頻繁には記述されないため、使用しにくくなっています。Visual Studio .NET 2003 での Web または Windows プロジェクトでは、Init イベントが扱うコードは[Web フォーム デザイナで生成されたコード]領域に配置されています。この領域は一般的に非表示で、生成されたコード用に予約されています。
これを解決するには、次の方法をお勧めします。
- CrystalReportViewer のすべてのバインド コードおよび設定コードを ConfigureCrystalReports() という名前のプライベート ヘルパー メソッドに展開します。
- [Web フォーム デザイナで生成されたコード]領域に、Page_Init() イベント ハンドラまたは OnInit() イベント起動メソッドの ConfigureCrystalReports() ヘルパー メソッドを呼び出す 1 行だけを配置します。
ConfigureCrystalReports() ヘルパー メソッドの作成と設定の手順は、「プロジェクトの設定」で説明されています。
チュートリアル
レポートの永続を完全に理解するために、次のチュートリアルで学習できます。
ReportDocument オブジェクト モデルでコード化する場合は、次のチュートリアルを使用します。