WebSurfer's Home

トップ > Blog 1   |   ログイン
APMLフィルター

Eval の引数

by WebSurfer 2010年8月20日 22:02

Eval の引数の文字列として使える文字に制限があることもついでに書いておきます。

Eval("xxxxx") の xxxxx は、先の記事で書きましたように、プロパティ名またはインデクサ名の文字列でなければならないそうです。

SQL Server の DB のデータを GridView に表示する場合、通常、xxxxx には DB のフィールド名が使用されます。

そこで、DB のフィールド名に "Name(ABC)" のように半角のカッコが入っていた場合どうなるでしょう?

Visual Studio のウィザードはなかなか賢くて、「Select ステートメントの構成」メニューで「テーブルまたはビューから列を指定します(T)」を選んで SELECT クエリを作ると、自動的に [NAME(ABC)] AS column1 というような別名を定義してくれるので問題ないです。(ただし、クエリビルダでクエリを組み立てるとダメです)

自分でクエリを組み立てる場合は要注意です。ちなみに、DB のフィールド名に "Name(ABC)" という文字列を使った場合、カッコが全角か半角かによって、結果は以下のように異なります。

SELECT クエリ Eval の引数 結果
[Name(ABC)]
半角カッコ
"Name(ABC)"
半角カッコ
System.ArgumentException: DataBinding: 'System.String' はインデックス付のアクセスを許可しません。
[Name(ABC)]
半角カッコ
"[Name(ABC)]"
半角カッコ
System.ArgumentException: NAME(ABC は、テーブル DefaultView の DataColumn でも DataRelation でもありません。
[Name(ABC)]
半角カッコ
"Name(ABC)"
全角カッコ
System.Web.HttpException: DataBinding: 'System.Data.DataRowView' には NAME(ABC) という名前のプロパティは含まれません。
[NAME(ABC)]
半角カッコ
"[Name(ABC)]"
全角カッコ
問題なし。
[Name(ABC)]
全角カッコ
"Name(ABC)"
全角カッコ
問題なし。
[Name(ABC)]
全角カッコ
"[Name(ABC)]"
全角カッコ
問題なし。

SELECT [NAME(ABC)] のカッコを半角から全角に変更してもデータを抽出できるのは、SQL Server のデフォルトの照合順序が Japanese_CI_AS(全角半角を区別しない)だからです。

Eval メソッドの引数で [ ] は特別な意味を持つらしいです。[ ] を使うと、SQL Server のデフォルトの照合順序にあわせて、全角文字と半角文字の区別をしなくなるような感じです。

一体どのように解釈されているのか訳が分かりませんが、とにかく、Eval メソッドの引数の中の文字に半角の( ) を使ってはダメで、使うと予期しない結果になるようです。

Tags: ,

ASP.NET

Eval, Bind の正体

by WebSurfer 2010年8月18日 16:17

データバインド式と Eval メソッドの話が出てきたので、ついでに Eval, Bind メソッドとは一体何かについて調べたことを書いておきます。

前に書いたことのおさらいですが、データバインド式は <%# デリミタと %> デリミタの間に記述され、Eval メソッドと Bind メソッドを使用します。

Eval メソッドは、一方向 (読み取り専用) バインディングを定義するために使用します。Bind メソッドは、双方向 (更新可能) バインディングに使用します。

Eval メソッド

以下は、MSDN ライブラリの「データ バインド式の概要」からの抜粋です。

"Eval メソッドは、名前付けコンテナの現在のデータ項目を参照する DataBinder オブジェクトの Eval メソッドを実行時に呼び出します。"

上記を、自分の理解(独断と偏見?)に基づき、具体的に書いてみます。

例えば以下のように、GirdView の ItemTemplate に配置した Label の Text プロパティにデータバインド式が設定してあったとします。

Text='<%# Eval("Price") %>'

これは DataBinder.Eval 静的メソッドを以下のように呼び出します。

Text='<%# DataBinder.Eval(Container.DataItem, "Price") %>'

第 1 引数に使われている Container は ASP.NET によって自動的に定義され初期化されます。使用されているデータバインドコントロールによって異なりますが、たとえば GridView を使用した場合、Container は GridViewRow になります(詳細後述)。

第 2 引数は、第 1 引数の Container.DataItem オブジェクトから値を取得するプロパティ名またはインデクサ名の文字列となります。例えば、DictionaryEntry.Key の Key などのプロパティ名、または DataRowView["Price"] の Price などのインデクサ名から成る文字列である必要があります。(2010/8/20 一部修正)

DataBinder.Eval メソッドは、第 1 引数で指定したオブジェクトに対して、第 2 引数で指定した名前を持つプロパティの値またはインデクサが指す値を取得して、Object 型として返します。先の DictionaryEntry および DataRowView を例にとると、下記のようになります。(2010/8/20 一部修正)

((DictionaryEntry)Container.DataItem).Key
((DataRowView)Container.DataItem)["Price"]

Eval メソッドで、プログラマが明示的にキャストを書かなくてもよいのはリフレクション機能を利用しているからだそうです。

Bind メソッド

DataBinder クラスには Bind というメソッドはありません。Bind メソッドの詳細が書いてあるドキュメントも見つかりませんでしたが、以下の点以外は Eval と同じと思われます。

GridView、DetailsView、FormView などのデータバインドコントロールのテンプレートに配置した TextBox や CheckBox で Bind を使用すると、それらへの入力値を抽出して、編集モードでは NewValues コレクション経由、挿入モードでは Values コレクション経由で、データソースコントロール(SqlDataSource など)に渡すことができます。

Container.DataItem

DataBinder.Evalメソッドの第 1 引数のオブジェクト Container.DataItem とは何でしょう?

例えばデータバインドコントロールに GridView を使用すると、ASP.NET が自動生成するコードで Container は以下のように定義され、自動的に初期化されるようになっています。

GridViewRow Container;

その他、Repeater, DataGrid, DataList, DetailsView, FormView, ListView などのデータバインドコントロールを用いると、適宜 RepeaterItem, DataGridItem, DataListItem, DetailsView, FormView, ListViewDataItem などが Container として定義され、初期化されるようになっています。

詳しくは、@IT のサイトの Container.DataItemの正体は? を参照してください。

------------ 2010/8/20 追記 ------------

DataBinder.Eval メソッドの第 2 引数は、MSDN ライブラリには "プロパティ名またはフィールド名から成る文字列" と書いてありましたが、インデクサの場合もありますので修正しました。

@IT のサイトの Webフォームにおけるデータ連結 を参照してください。

Tags: ,

ASP.NET

データバインド式

by WebSurfer 2010年8月17日 23:44

<%# 文字と %> 文字で囲んで用いるデータバインド式を使用すると、ページで DataBind メソッドが呼び出されたときに、サーバーコントロールプロパティとデータソースの間にバインディングが作成されます。

Eval や Bind メソッドを TextBox や Label コントロールの Text プロパティに以下のように設定して使うことが多いと思います。

Text='<%# Eval("Name") %>'

上記のような単純な使い方なら間違うことはなさそうですが、複雑な文字列を組み立てる場合は、別にそのためのメソッドを定義して用いるのがよさそうです。

例えば、以下のようにメソッドで文字列を組み立てて、

string Description(string s, int n)
{
  return String.Format("項目 {0} の数量は {1} です。", s, n);
}

それを以下のように設定できます。

Text='<%# Description((string)Eval("Name"), (int)Eval("Qty")) %>'

ただし、メソッドを使うまでもない簡単な文字列なら、例えば以下のようにする方がよいと思います。

Text='<%# "Name:" + Eval("Name") %>'

なお、以下のようにするのは、データバインド式を含めた全体が文字列として解釈されてしまうので、うまくいきません。

Text='Name:<%# Eval("Name") %>'

ありそうな間違いは、ImageUrl や NavigateUrl に、例えば、以下のように設定するケースでしょうか。

ImageUrl='~/Images/<%# Eval("Name") %>'

この結果は以下のようになってしまいます。

src="Images/%3C%25#%20Eval(%22Name%22)%20%25%3E"

(注)ImageUrl の場合は UrlEncode されるので、< や % などが %3C と %25 になります。一方、NavigateUrl の方は何故か UrlEncode されません。

Tags: ,

ASP.NET

About this blog

2010年5月にこのブログを立ち上げました。主に ASP.NET Web アプリ関係の記事です。

Calendar

<<  2024年4月  >>
31123456
78910111213
14151617181920
21222324252627
2829301234
567891011

View posts in large calendar