トップ回答者
FormViewでテーブルコントロール内の値が渡らない

質問
-
FormViewで表の見出しの参照・編集するページを作成しました。
列の表示/非表示をするためテンプレート内でテーブルコントロールを使用しています。
しかし、テーブルコントロール内に配置したテキストボックスには
表示できているのに、登録するとカラになります。
テキストボックスをテーブルの外に出すと登録できます。
パネルに配置しても登録できます。
なんでテーブルコントロールはダメなんでしょうか。以下コード--------
<asp:DropDownList ID="DropDownList1" runat="server" DataSourceID="SqlDataSource2"
DataTextField="TITLE" DataValueField="CODE" AutoPostBack="True">
</asp:DropDownList><asp:SqlDataSource ID="SqlDataSource2" runat="server" ConnectionString="<%$ ConnectionStrings:xxxx %>"
SelectCommand="SELECT * FROM T_MIDASI"></asp:SqlDataSource>
<asp:FormView ID="FormView1" runat="server" DataSourceID="SqlDataSource1">
<EditItemTemplate>
TITLE:<asp:TextBox ID="TITLETextBox" runat="server" Text='<%# Bind("TITLE") %>'></asp:TextBox><br />
<asp:Table ID="Table1" runat="server" GridLines="Both">
<asp:TableRow ID="TableRow1" runat="server">
<asp:TableCell ID="TableCell1" runat="server" Visible='<%# Eval("COL1") %>'>
TEXT1:<asp:TextBox ID="TEXT1TextBox" runat="server" Text='<%# Bind("TEXT1") %>'></asp:TextBox><br />
</asp:TableCell>
<asp:TableCell ID="TableCell2" runat="server" Visible='<%# Eval("COL2") %>'>
TEXT2:<asp:TextBox ID="TEXT2TextBox" runat="server" Text='<%# Bind("TEXT2") %>'></asp:TextBox><br />
</asp:TableCell>
<asp:TableCell ID="TableCell3" runat="server" Visible='<%# Eval("COL3") %>'>
TEXT3:<asp:TextBox ID="TEXT3TextBox" runat="server" Text='<%# Bind("TEXT3") %>'></asp:TextBox><br />
</asp:TableCell>
</asp:TableRow>
<asp:TableRow ID="TableRow2" runat="server">
<asp:TableCell runat="server" Visible='<%# Eval("COL1") %>' Text=" "></asp:TableCell>
<asp:TableCell runat="server" Visible='<%# Eval("COL2") %>' Text=" "></asp:TableCell>
<asp:TableCell runat="server" Visible='<%# Eval("COL3") %>' Text=" "></asp:TableCell>
</asp:TableRow>
</asp:Table>
<asp:LinkButton ID="UpdateButton" runat="server" CausesValidation="True" CommandName="Update" Text="更新"></asp:LinkButton>
<asp:LinkButton ID="UpdateCancelButton" runat="server" CausesValidation="False" CommandName="Cancel" Text="キャンセル"></asp:LinkButton>
</EditItemTemplate>
<InsertItemTemplate>---(略)</InsertItemTemplate>
<ItemTemplate>---(略)</ItemTemplate>
</asp:FormView>
<asp:SqlDataSource ID="SqlDataSource1" runat="server" ConnectionString="<%$ ConnectionStrings:xxxx %>"
SelectCommand="SELECT T_MIDASI.TITLE
, CONVERT(bit, 1) AS COL1, CONVERT(bit, 0) AS COL2, CONVERT(bit, 1) AS COL3
, T_MIDASI.TEXT1, T_MIDASI.TEXT2, T_MIDASI.TEXT3
FROM T_MIDASI
WHERE (T_MIDASI.CODE = @CODE)"
UpdateCommand="UPDATE T_MIDASI SET TITLE = @TITLE
, TEXT1 = @TEXT1, TEXT2 = @TEXT2, TEXT3 = @TEXT3
WHERE (CODE = @CODE)">
<UpdateParameters>
<asp:Parameter Name="TITLE" />
<asp:Parameter Name="TEXT1" />
<asp:Parameter Name="TEXT2" />
<asp:Parameter Name="TEXT3" />
<asp:ControlParameter ControlID="DropDownList1" DefaultValue="0" Name="CODE" PropertyName="SelectedValue" Type="Int32" />
</UpdateParameters>
<SelectParameters>
<asp:ControlParameter ControlID="DropDownList1" DefaultValue="0" Name="CODE" PropertyName="SelectedValue" Type="Int32" />
</SelectParameters>
</asp:SqlDataSource>
回答
-
色々と試行錯誤したところ、テンプレート内に配置されたコントロールが、プロパティとして読み込まれると <%# Bind() %> による双方向データバインディングの記述が無視され、IBindableTemplate.ExtractValues によって、値が取得できなくなるようです。この動きからすると、ASP.NET の .aspx からソースコードを生成する際に、子コントロールの検索先としての考慮漏れによる不具合なかんじがします。ParseChildrenAttribute と子オブジェクトの設定について、標準のコントロールをすべて確認してみると、<asp:Table> 以外には、<asp:LoginView> が唯一該当するようで、同様の問題が発生することが確認できました。まとめると以下のようなかんじでしょうか。症状特定の状況下で <%# Bind(xxx) #%> 構文による双方向のデータバインディングが正常に動作しない再現条件データバインディングを実施しているコードが、・テンプレートの内部である・子コントロールをプロパティとして保持するコンテナ内に配置しているの2点をともに満たす場合。標準のコントロールでは、<asp:Table> と <asp:LoginView> の2つが該当するコンテナ。回避策A. コンテナコントロールを <table>、<asp:Panel> などに変更するまたは、B. 双方向データバインディングを利用せず、ControlParameter や、Updating イベントなどを利用してデータの更新を実施する
すべての返信
-
trapemiya さんからの引用 UpdateParametersがおかしいですね。
DataBinding を利用しているのでぜんぜんおかしくないと思います。むしろ、UpdateParameters は外部の DropDownList1 を除いて空であってもかまわないはずです。
FormView は1行のデータのみなので DataBinding からのデータプッシュを、asp:ControlParameter を使用したコントロールからのプルに変更しても偶然うまく動くことができますが、GridView なんかだと選択行からデータプッシュの提供を受けないと、コントロールからプルするようにするのは手間がかかりますし、回避方法としてはありかもしれませんが、修正方法としては間違っていると思います。
天河さんは FormView での再現コードを示されていますが、この問題は GridView なんかでも同様に発生します。DataBinding を含んだテンプレートに Table を含めると、IBindableTemplate の ExtractValues が期待通りに動作しません。(というところまでしか調べていないので、解決方法は知らないんですが)
-
天河さんのコードではテーブルにnullが保存されてしまい、結果的にnullが表示されているので、何も表示されていないように見えます。これを回避するには、WebコントロールのTable(ツールボックスの標準にあるTable)ではなく、HTML要素のTable(ツールボックスのHTMLにあるTable)を使用するとうまくいきます。
このことから、単に私はNamingContainerの問題であろうと判断したのですが、ExtractValuesが動作しないという問題があるのですね。この辺りの情報はどこを調べればよいでしょうか?
ただ、少なくとも私がテストしている限りでは、正常に動いているように見えます。 -
trapemiya さんからの引用 天河さんのコードではテーブルにnullが保存されてしまい、結果的にnullが表示されているので、これはどういうことだろう? 適当に手元のテーブルで試すかぎり、読み込み側は正常に動作していて問題なくデータベースの値が表示されます。天河さんも「表示できているのに」と書いておられるので null が表示されるようなことは発生していないと思います。trapemiya さんからの引用 これを回避するには、WebコントロールのTable(ツールボックスの標準にあるTable)ではなく、HTML要素のTable(ツールボックスのHTMLにあるTable)を使用するとうまくいきます。そうですね、ただ、天河さんが行われているような Visible のコントロールには、asp:Table コントロールのほうが便がよいので、asp:Table のかわりに asp:Panel を使用されるとよいかもしれません。css を使用すれば asp:Panel を asp:Table のように並べるのは、そんなに難しくないように思います。trapemiya さんからの引用 このことから、単に私はNamingContainerの問題であろうと判断したのですが、ExtractValuesが動作しないという問題があるのですね。DataBinding では NamingContainer は関係ないですね。DataView とコントロールを繋ぐコードの生成は、バインディング構文を含むコントロールの単位で行われるので、DataSource にパラメータを記述する必要もありませんし、GridView などのように複数の列に対してもうまく動きます。問題の根底は、コントロールビルダかテンプレートビルダの動作にあると思いますが、なんらかの仕様による制限なのか、設定値で回避可能な制限なのか、ASP.NET の不具合なのかは、私にはちょっと判断できないです。問題が再現するコントロールが、asp:Table 以外に存在するかどうかも判断できません。extractValues に関しては、「完全なコンパイルコードの表示」を使うと、あきらかに間違った実装が生成されているのを確認することができます。設定側メソッドの実装は正常なので、コントロールビルダのツリーは正常に生成されていて、テンプレートコントロールの実装を吐き出している System.Web.Compilation.TemplateControlCodeDomTreeGenerator あたりの動作に問題がありそうな雰囲気です。 -
色々と試行錯誤したところ、テンプレート内に配置されたコントロールが、プロパティとして読み込まれると <%# Bind() %> による双方向データバインディングの記述が無視され、IBindableTemplate.ExtractValues によって、値が取得できなくなるようです。この動きからすると、ASP.NET の .aspx からソースコードを生成する際に、子コントロールの検索先としての考慮漏れによる不具合なかんじがします。ParseChildrenAttribute と子オブジェクトの設定について、標準のコントロールをすべて確認してみると、<asp:Table> 以外には、<asp:LoginView> が唯一該当するようで、同様の問題が発生することが確認できました。まとめると以下のようなかんじでしょうか。症状特定の状況下で <%# Bind(xxx) #%> 構文による双方向のデータバインディングが正常に動作しない再現条件データバインディングを実施しているコードが、・テンプレートの内部である・子コントロールをプロパティとして保持するコンテナ内に配置しているの2点をともに満たす場合。標準のコントロールでは、<asp:Table> と <asp:LoginView> の2つが該当するコンテナ。回避策A. コンテナコントロールを <table>、<asp:Panel> などに変更するまたは、B. 双方向データバインディングを利用せず、ControlParameter や、Updating イベントなどを利用してデータの更新を実施する
-
K.Takaokaさんの言われている事がようやく理解できました。根本的に私の早合点&勘違いがありました。ごめんなさい。
天河さんのupdate文のパラメータ指定で問題ありません。訂正いたします。m(_ _)m
私が示したのは、K.Takaokaさんが書かれている回避策Bの、ControlParameterを使用した場合でした。K.Takaoka さんからの引用
テンプレート内に配置されたコントロールが、プロパティとして読み込まれると <%# Bind() %> による双方向データバインディングの記述が無視され、IBindableTemplate.ExtractValues によって、値が取得できなくなるようです。
実際、テストしましたが、FromViewの更新をクリックすると、テーブルの当該レコードの表示されているフィールドは、全てnullで更新されていました。
よく調べていませんが、雰囲気は障害っぽいですね。 -
K.Takaoka様、trapemiya様、ありがとうございました。
きっちりまとめていただき大変スッキリしました。
結局以下のようにHTMLのTABLEでセルを runat="server" にして対処しました。<table>
<tr>
<td runat="server" id="TableCell1" visible='<%# Eval("COL1") %>'>
TEXT1:<asp:TextBox ID="TEXT1TextBox" runat="server" Text='<%# Bind("TEXT1") %>'></asp:TextBox>
</td>本当にありがとうございました。