きよくらの備忘録

「三日坊主と呼ばせない!日記」改め。主にソフトウェア開発関連の話題。

Visual Studio 2003(ASP.NET)のデザイナが開けない。事がある。

そろそろ.Net Framework 2.0どころか、3.0に移ろうとしている世の中なのかもしれませんが、私の仕事のメインはまだまだ1.1なもので、色々とかゆいところに手が届かないと言うか、不具合と言うかがちらほら見られ、もうおそらく修正されることは永遠に無いと思われるVisual Studio .Net 2003でASP.NETの開発を行っています。

そんな中で、「しっかりしてくれよ……」と言いたくなる事例を一つ。
愚痴に近いですが、初めて遭遇したら一寸はまるかも知れませんし。


事象:

HTMLビューで弄った後、デザイナビューで表示しようとすると、以下のメッセージが表示され、HTMLビューからデザイナビューに切りかえれなくなる。

「デザイナビューで開けませんでした。'<% ... value...%>'ブロック内にあるそれぞれの値を、引用符で区切ってください。」



最近やってて実際に起こったのは、DataGridのテンプレート列中に配置するHTML部品(クライアント実行)として、以下を記述した際。


<input type="button" value="実行"
onClick="Javascript:setHogeHoge('<%# DataBinder.Eval(Container , "DataItem.ID") %>');">*1

エラーとなった原因は、おそらく、デザイナがHTMLを解釈しようとした時に、<% %>内にある引用符と、『onClick="』の引用符を続けて解釈した結果、以下のようになり、Visual Studio的に「HTMLの文法的に理解不能でレンダリング不能や!!」と弱音を吐いたせいだ、と思われます。


※同色の『"』が対応する引用符、灰色の部分が引用符でクォートされた文字。
< 〜 onClick="Javascript:setHogeHoge('<%# DataBinder.Eval(Container , "DataItem.ID") %>);'">

もちろんコレは、DataGridとか関係なく、他のところに書いても同様で、HTML部品の属性値の中に、引用符アリのコードをバインド使用とすると普通に(?)発生します。

対処法としては、いくつかありますが、状況によって取れる選択肢は限られてきます。

−− 
 
1.引用符を変える
単純に以下のような場合であれば、引用符をシングルクォートに変更するだけで対処可能です。


<input type="text" value='<%# DataBinder.Eval(Container , "DataItem.ID") %>'>
ただし、欠点として、

    1. Visual Studioが出力するタグのデフォルトの引用符が『"』なので、そこだけ変えると解りづらくなる。
    2. XHTMLだと、『'』のクォートは仕様外(これはまあ、そもそもVS2003ではXHTML Validなのを出力するのは所詮無理なので気にしなくても良いかも)
    3. 今回の私の例のように、Javascriptの関数の引数として使う場合、Javascript側でもクォートしないといけないので、その場合はこの手段は不可能

というのも、思い浮かびます。
(今回の場合、当然、3番目のヤツに引っ掛かるので、この手は使えませんでした)
 
 
2.部品をサーバコントロール化(runat="server"を記述)し、ItemDataBoundイベントハンドラとかでAttribute.Addする
ちょっと面倒だけれど、そうすれば問題ありません。
が、もちろん

    1. (ほかにItemDataBound時に行う処理が内のであれば)これだけの処理のために、記述しないといけないコードが多くなる。
    2. オーバーヘッドも気になる。(DataGridであれば、対象がItem行なのかどうかいった判定処理も書かないといけない……ですよね?)
    3. そもそも、コードビハンドしてる意味が薄くなって嫌(何らか計算したり比較してたりするわけでなくて、単に値をバインドしているだけなのだから、aspxファイルの内の記述だけで行ければ行きたいです。)

という思いが出てきます。
例えば、何か他にもItemDataBound内で処理(サーバサイドコントロールに何か処理する)必要があるならそこでまとめて書くの普通にやることだと思いますが、他はすべてプロパティビルダなどで設定したりしてaspxファイル内に書いているのに、このためだけに態々イベントハンドラ何に書くのも気持ち悪いと言うか、保守性に悪影響を及ぼす恐れがあります。
また、そもそも私は、<asp:hoge〜で無い、単なるHTML部品にrunat="server"を書くのには抵抗があります*2。コードビハインドの理念(?)に反している気がします*3
 
 
3.リテラル値を変数や定数に置く
<%# ... %>の中で引用符に囲まれているということは、当然、文字リテラルなので、以下のようにコード側で定数化してやって、


Protected Const DG_BIND_LABEL As String = "DataItem.ID"
HTML側には以下のように書く。

<〜 onClick="Javascript:setHogeHoge('<%# DataBinder.Eval(Container , DG_BIND_LABEL) %>');">
これで、問題なくデザインビューで開けますし、この程度ならコード側に記述しても、特に問題ないと思います。たぶん。

−−
結局、3番目が、見やすさ/記述の少なさ/処理のわかりやすさ、そして僕の好み(重要)などを満たしたので、今回を採用しました。というかたぶん、私はの場合は基本的にはこれで行くことになると思います*4

というかぶっちゃけ、<%# %>内にはあらゆるコードが入る可能性がある(というかそういう仕様)なんだから、<%# %>内をHTMLと続けて解釈するというのは、そもそもバグ(仕様というなら、そりゃ、仕様バグだ)だと思うのです。
#が、もう、これは直らないんだろうなぁ……。

*1:何をやりたかったかというと、DataGrid内のテンプレート列に、HTML部品のinput type=buttonを配置し、そのonClickイベントハンドラ内でコールするJavascriptの引数として、DataGridにバインドしてある値を書き出す、という処理。ボタンをサーバサイド部品化して、DataGridのItemDataBoundイベント時にAttribute.Addする手もあるけれども、PostBackしない様にreturn false書くのも気持ち悪いし面倒くさいので、こうしたかった。

*2:もちろん、form要素は別ですが

*3:それに、HTML部品に適当にrunat="server"をつけておいても、何かの拍子で勝手にrunat属性が削除されていることがあったりしましたし。書いてた部品が悪いだけかもしれませんが

*4:例外としては、バインドする対象がサーバサイドコントロールの場合で、他にもItemDataBoundイベント内で記述する処理がある場合など。