ASPに深く入り込む.NETデータバインディング(中)——データ双方向バインディングメカニズム
13399 ワード
前回の「ASPに深く入り込む.NETデータバインド(上)」では、次のように分析した.NETのデータバインド構文のいくつかの内部メカニズム.簡単に言えばASP.NETは実行時にページの動的コンパイルを完了し,データバインド構文を含むページの各種サーバ側コードを解析した.データバインディングの構文は「%#%」>「コードブロック」であるが、生成されたコードではサーバ側のコントロールとDataBindingイベントでDataBinderを呼び出す.Evalメソッドは、データのバインド作業を完了します.すべてのデータバインドテンプレートコントロールは、データの一方向バインドを行うためにこのようなメカニズムを使用する.NET 2.0には双方向のデータバインディング方式が追加され、主にGridView、DetailsView、FormViewなどのデータコンテナコントロールで使用されています.DataSourceControlと組み合わせると、入力コントロールの値を手動で巡回する必要がなく、データの更新とコミットを簡単に行うことができます.このような双方向データバインディングでは、ASP.NETはどのような仕事をして、コントロールとフィールドの値と対応関係を透明に入力して、DataSouceControlでデータ項目の修正前の値と修正後の値を簡単に得ることができますか?ページコードから始めましょう.
あるページでは、上記のようなDetailsViewコントロールを定義し、このコントロールにDetailsDataSource 1としてIDが付けられたDataSouceControlコントロールを指定します.このコントロールは、私たちが定義したDataSourceControlで、返されるデータフィールドには、「ID」、「電流{a}」、「電圧(v)」、「注釈'」、「名前」が含まれます.私はDetailsViewのAutoGenerateRowsプロパティの値を設定していません.デフォルトでは、これらのフィールドの対応するデータ表示と入力コントロールを自動的に生成します.このほか、編集テンプレートを指定するデータテンプレートフィールドも追加しました.編集テンプレートでは<%#Bind(")%>という構文を使ってtextBox 1を「[電流{a}」フィールドに双方向にバインドしました.
なぜここのフィールドにはいくつかの特殊なものがありますか?バインド構文を分析する以外に、データバインド構文を使用してデータをバインドできない特殊な文字をテストすることを意図していたからです.これは次の文章で具体的に紹介します.
BindはEvalとは異なり、このようなBindはPageやTemplateControlの方法ではありません.実際にはASP.NETの双方向データバインディングでは,このような関数は存在せず,その存在はASPに伝えるだけである.NETがページクラスを動的にコンパイルする場合,この構文を一定のコードフォーマットにコンパイルし,双方向データ交流の目的を達成するためにいくつかの関数エージェントを生成する.
では、このコードを動的にコンパイルして生成したサーバコードはどうなっているのでしょうか.ダイナミック・プログラム・セットを逆コンパイルします.DetailsViewを作成するための__が表示されます.BuildControldetailsViewのプライベートメソッドは、ここで他の内部メソッドに呼び出されます.これらのメソッドを視線に干渉させないで、上記のテンプレートフィールドを作成する方法を直接見つけます.
ここでまずこれをBuildControl__control 6は、ヘッダテンプレートの内容、すなわち、上述した「電流:」フィールドヘッダーを作成するためのプロキシ関数として使用される.それからEditItemTemplateを作成します.このテンプレートはいくつかの仲介テンプレートに置き換えられています.私たちはthisに関心を持つ必要があります.BuildControl__コントロール7と_ExtractValues__コントロール7でいいです.BuildControl__コントロール7は、データフィールドを編集するために、データフィールドの値を入力コントロールに表示する(入力コントロールの初期化、すなわちフィールド値を入力コントロールにバインドする).そして_ExtractValues__コントロール7は、データをコミットするときに、このテンプレート内のすべての双方向バインドフィールドを見つけるには、これらのフィールドの値をバインドフィールド名Keyとし、入力コントロールの値をValueとしてIOrderedDictionary辞書に追加します.DetailsViewなどのデータバインドコントロールは、これらの委任エージェントを呼び出して、双方向にバインドされたすべてのフィールドの最新の値を収集します.次は、2つの関数のコードクリップです.
上記のコードクリップから分かるように、ASP.NETダイナミックコンパイラは、Bind構文を出力のバインドと入力コントロール値の読み取りの2つの部分に分割します.バインド出力部は前編で説明したメカニズムと全く同じであり、DataBinderを呼び出すものでもある.Evalメソッドはデータをバインドします.読み込み入力コントロール値は、ページ上のコントロールのタイプとバインドされたコントロール属性名に基づいて、強いタイプのコントロール属性読み込みコードを生成し、コントロールの値をdictionayに保存して戻ります.コンテナコントロールがこれらの値を統合して対応するDataSouceControlコントロールに伝える方法は全く分かりません.
データコンテナコントロールがDataSouceControlと連携して機能する方法については、ここで分析するポイントではありません.しかし、簡単にワークフローを説明することができます.DetailsViewのデータ更新を例に挙げると、DetailsViewのソースコードを逆コンパイルすることで、HandleUpdateというプライベートメソッドが見つかります.このメソッドでは、データ項目の更新前の値を処理します(Web環境で更新前の値をどのように保存するかは、ViewStateの強力な機能に頼る必要があります).と更新された値(ExtractRowValues関数によって上記のように生成された__ExtractValues__control7エージェント関数を呼び出してすべての双方向バインドフィールドの値を収集してNewValuesに保存します)を呼び出し、2つの異なるIOrderedDictionaryオブジェクト(OldValues,NewValues)にそれぞれ保存します.次に、対応するDataSouceViewのUpdateメソッドを呼び出し、元のフィールド値と新しいフィールド値と必要なパラメータを入力します.DataSourceViewのメソッドを書き換えることで、更新する必要があるすべてのフィールドの元の値と新しい値を取得し、どのフィールド値が変化したかを比較できます.NBEarDataSourceコントロールは、このようなメカニズムを利用して、DataSourceControlとDataSourceViewを直接再利用して、データの全自動修正と追加スキームを達成します.
ここで、GridView、DetailsViewでは、必ずしも<%#Bind(")%>構文を使用してデータの双方向バインディングを実現する必要はありません.フィールドの双方向バインディングは、テンプレートコントロールのバインディング構文の代わりにBoundFieldおよびそのサブコントロールを使用することができます.同様に、双方向バインディングの目的を達成することができますが、テンプレートがなくて柔軟です.異なるバージョンのフィールド値にアクセスするのも同様のメカニズムです.
この部分は動的および内部コードに関連しているため,これらのコードを直接読まなければ理解しにくいと推定される.最後に簡単にまとめてみましょう:ASP.NETはテンプレート内でフィールドを双方向にバインドし、<%#Bind()%>という構文を使用しますが、Bindは関数ではなくキーワードとして理解する必要があります.ASPにあるのでNETのコントロールには、この関数は存在しません.ASP.NET実行時にページコードをコンパイルすると、Bindキーワードのコードは2つの部分としてコンパイルされます.一部は一方向バインドコードです.別の部分では、対応する入力コントロールのバインディング属性を読み込み、バインディングフィールド名をKeyとし、IOrderedDictionaryに追加してデータコンテナコントロール(GridView,DetailsView,FormView)などに収集して返し、処理させる.
全体的にASP.NET 2.0の双方向バインディングメカニズムは、データを提出する際に大きな便利さをもたらしました.DataSourceControlのモデルを排斥する人もいますが、合理的な応用が開発効率を大幅に向上させることは否定できません.この2編の紹介を通じて、私たちはASPに対してNETデータバインドメカニズムはより多くの認識を持っている.次の記事では、データバインド方法、パフォーマンス、フィールド名の限界などに関するトピックについて説明します.
サンプルエンジニアリングを添付、本明細書の分析ページはDefault 3である.aspxとApp_Web_ryn6wtvv.dllプログラムセット.
1: <asp:DetailsDataSouce ID="DetailsDataSouce1" runat="server">
2: </asp:DetailsDataSouce>
3: <asp:DetailsView ID="detailsView" runat="server" DefaultMode="Edit" DataSourceID="DetailsDataSouce1">
4: <Fields>
5: <asp:TemplateField>
6: <HeaderTemplate>
7: :</HeaderTemplate>
8: <EditItemTemplate>
9: <asp:TextBox ID="textBox1" runat="server" Text='<%# Bind("[ {a}]") %>'></asp:TextBox>
10: </EditItemTemplate>
11: </asp:TemplateField>
12: </Fields>
13: </asp:DetailsView>
あるページでは、上記のようなDetailsViewコントロールを定義し、このコントロールにDetailsDataSource 1としてIDが付けられたDataSouceControlコントロールを指定します.このコントロールは、私たちが定義したDataSourceControlで、返されるデータフィールドには、「ID」、「電流{a}」、「電圧(v)」、「注釈'」、「名前」が含まれます.私はDetailsViewのAutoGenerateRowsプロパティの値を設定していません.デフォルトでは、これらのフィールドの対応するデータ表示と入力コントロールを自動的に生成します.このほか、編集テンプレートを指定するデータテンプレートフィールドも追加しました.編集テンプレートでは<%#Bind(")%>という構文を使ってtextBox 1を「[電流{a}」フィールドに双方向にバインドしました.
なぜここのフィールドにはいくつかの特殊なものがありますか?バインド構文を分析する以外に、データバインド構文を使用してデータをバインドできない特殊な文字をテストすることを意図していたからです.これは次の文章で具体的に紹介します.
BindはEvalとは異なり、このようなBindはPageやTemplateControlの方法ではありません.実際にはASP.NETの双方向データバインディングでは,このような関数は存在せず,その存在はASPに伝えるだけである.NETがページクラスを動的にコンパイルする場合,この構文を一定のコードフォーマットにコンパイルし,双方向データ交流の目的を達成するためにいくつかの関数エージェントを生成する.
では、このコードを動的にコンパイルして生成したサーバコードはどうなっているのでしょうか.ダイナミック・プログラム・セットを逆コンパイルします.DetailsViewを作成するための__が表示されます.BuildControldetailsViewのプライベートメソッドは、ここで他の内部メソッドに呼び出されます.これらのメソッドを視線に干渉させないで、上記のテンプレートフィールドを作成する方法を直接見つけます.
1: [DebuggerNonUserCode]
2: private TemplateField __BuildControl__control5()
3: {
4: TemplateField field = new TemplateField();
5: field.HeaderTemplate = new CompiledTemplateBuilder(new BuildTemplateMethod(this.__BuildControl__control6));
6: field.EditItemTemplate = new CompiledBindableTemplateBuilder(new BuildTemplateMethod(this.__BuildControl__control7), new ExtractTemplateValuesMethod(this.__ExtractValues__control7));
7: return field;
8: }
ここでまずこれをBuildControl__control 6は、ヘッダテンプレートの内容、すなわち、上述した「電流:」フィールドヘッダーを作成するためのプロキシ関数として使用される.それからEditItemTemplateを作成します.このテンプレートはいくつかの仲介テンプレートに置き換えられています.私たちはthisに関心を持つ必要があります.BuildControl__コントロール7と_ExtractValues__コントロール7でいいです.BuildControl__コントロール7は、データフィールドを編集するために、データフィールドの値を入力コントロールに表示する(入力コントロールの初期化、すなわちフィールド値を入力コントロールにバインドする).そして_ExtractValues__コントロール7は、データをコミットするときに、このテンプレート内のすべての双方向バインドフィールドを見つけるには、これらのフィールドの値をバインドフィールド名Keyとし、入力コントロールの値をValueとしてIOrderedDictionary辞書に追加します.DetailsViewなどのデータバインドコントロールは、これらの委任エージェントを呼び出して、双方向にバインドされたすべてのフィールドの最新の値を収集します.次は、2つの関数のコードクリップです.
1: [DebuggerNonUserCode]
2: private TextBox __BuildControl__control8()
3: {
4: TextBox box = new TextBox();
5: box.TemplateControl = this;
6: box.ApplyStyleSheetSkin(this);
7: box.ID = "textBox1";
8: box.DataBinding += new EventHandler(this.__DataBinding__control8);
9: return box;
10: }
11: public void __DataBinding__control8(object sender, EventArgs e)
12: {
13: TextBox box = (TextBox) sender;
14: IDataItemContainer bindingContainer = (IDataItemContainer) box.BindingContainer;
15: if (this.Page.GetDataItem() != null)
16: {
17: box.Text = Convert.ToString(base.Eval("[ {a}]"), CultureInfo.CurrentCulture);
18: }
19: }
1: [DebuggerNonUserCode]
2: public IOrderedDictionary __ExtractValues__control7(Control __container)
3: {
4: TextBox box = (TextBox) __container.FindControl("textBox1");
5: OrderedDictionary dictionary = new OrderedDictionary();
6: if (box != null)
7: {
8: dictionary["[ {a}]"] = box.Text;
9: }
10: return dictionary;
11: }
上記のコードクリップから分かるように、ASP.NETダイナミックコンパイラは、Bind構文を出力のバインドと入力コントロール値の読み取りの2つの部分に分割します.バインド出力部は前編で説明したメカニズムと全く同じであり、DataBinderを呼び出すものでもある.Evalメソッドはデータをバインドします.読み込み入力コントロール値は、ページ上のコントロールのタイプとバインドされたコントロール属性名に基づいて、強いタイプのコントロール属性読み込みコードを生成し、コントロールの値をdictionayに保存して戻ります.コンテナコントロールがこれらの値を統合して対応するDataSouceControlコントロールに伝える方法は全く分かりません.
データコンテナコントロールがDataSouceControlと連携して機能する方法については、ここで分析するポイントではありません.しかし、簡単にワークフローを説明することができます.DetailsViewのデータ更新を例に挙げると、DetailsViewのソースコードを逆コンパイルすることで、HandleUpdateというプライベートメソッドが見つかります.このメソッドでは、データ項目の更新前の値を処理します(Web環境で更新前の値をどのように保存するかは、ViewStateの強力な機能に頼る必要があります).と更新された値(ExtractRowValues関数によって上記のように生成された__ExtractValues__control7エージェント関数を呼び出してすべての双方向バインドフィールドの値を収集してNewValuesに保存します)を呼び出し、2つの異なるIOrderedDictionaryオブジェクト(OldValues,NewValues)にそれぞれ保存します.次に、対応するDataSouceViewのUpdateメソッドを呼び出し、元のフィールド値と新しいフィールド値と必要なパラメータを入力します.DataSourceViewのメソッドを書き換えることで、更新する必要があるすべてのフィールドの元の値と新しい値を取得し、どのフィールド値が変化したかを比較できます.NBEarDataSourceコントロールは、このようなメカニズムを利用して、DataSourceControlとDataSourceViewを直接再利用して、データの全自動修正と追加スキームを達成します.
ここで、GridView、DetailsViewでは、必ずしも<%#Bind(")%>構文を使用してデータの双方向バインディングを実現する必要はありません.フィールドの双方向バインディングは、テンプレートコントロールのバインディング構文の代わりにBoundFieldおよびそのサブコントロールを使用することができます.同様に、双方向バインディングの目的を達成することができますが、テンプレートがなくて柔軟です.異なるバージョンのフィールド値にアクセスするのも同様のメカニズムです.
この部分は動的および内部コードに関連しているため,これらのコードを直接読まなければ理解しにくいと推定される.最後に簡単にまとめてみましょう:ASP.NETはテンプレート内でフィールドを双方向にバインドし、<%#Bind()%>という構文を使用しますが、Bindは関数ではなくキーワードとして理解する必要があります.ASPにあるのでNETのコントロールには、この関数は存在しません.ASP.NET実行時にページコードをコンパイルすると、Bindキーワードのコードは2つの部分としてコンパイルされます.一部は一方向バインドコードです.別の部分では、対応する入力コントロールのバインディング属性を読み込み、バインディングフィールド名をKeyとし、IOrderedDictionaryに追加してデータコンテナコントロール(GridView,DetailsView,FormView)などに収集して返し、処理させる.
全体的にASP.NET 2.0の双方向バインディングメカニズムは、データを提出する際に大きな便利さをもたらしました.DataSourceControlのモデルを排斥する人もいますが、合理的な応用が開発効率を大幅に向上させることは否定できません.この2編の紹介を通じて、私たちはASPに対してNETデータバインドメカニズムはより多くの認識を持っている.次の記事では、データバインド方法、パフォーマンス、フィールド名の限界などに関するトピックについて説明します.
サンプルエンジニアリングを添付、本明細書の分析ページはDefault 3である.aspxとApp_Web_ryn6wtvv.dllプログラムセット.