C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[6]: ASP.NETでの動的コントロールについて初歩的な質問


(過去ログ 126 を表示中)

[トピック内 8 記事 (1 - 8 表示)]  << 0 >>

■74799 / inTopicNo.1)  ASP.NETでの動的コントロールについて初歩的な質問
  
□投稿者/ mura (1回)-(2015/01/29(Thu) 19:54:21)

分類:[ASP.NET (VB)] 

Visual Studio 2008 Pro
.NET Framework 3.5 SP1

これまでWindowsフォームアプリケーションしか開発したことがなかったのですが
ASP.netでWebアプリケーションを開発することになり、かなり悩んでおります

動作時に動的にテキストボックスを追加し、入力や参照を行いたく、サンプルを
調べていたところ下記のようにするとうまくいくことがわかりました。

フォームには最初からLabel1とButton1があり、動的にテキストボックスを追加し、
Button1が押されたらその内容をLabel1に表示するというものです。

------------------------------------------------------------------------
Partial Public Class TEST

    Inherits System.Web.UI.Page

    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load

        If Not Page.IsPostBack Then
            MakeTextBox()
        Else
            MakeTextBox()               '[1]
        End If

    End Sub

    Private Sub MakeTextBox()

        Dim tbx As New TextBox
        tbx.ID = "DynamicTextBox"
        tbx.Text = "初期値"             '[3]
        form1.Controls.Add(tbx)

    End Sub

    Protected Sub Button1_Click(ByVal sender As Object, ByVal e As EventArgs) Handles Button1.Click

        Dim tbx As New TextBox
        tbx = CType(FindControl("DynamicTextBox"), TextBox)
        Label1.Text = tbx.Text          '[2]

    End Sub

End Class
------------------------------------------------------------------------

疑問点が2つあります

【疑問1】
上記ソースを動かすと、期待した動作をします。テキストボックスにABCと入力して
ボタンを押すと、ラベルにはABCと表示されます。

しかし、実際にはボタンを押すとまずPage_Loadが呼び出され、そこからMakeTextBoxが
処理され、それからButton1_Clickが処理されるという順番で動くようです。
つまり、[2]の部分より[3]の部分のほうが先に動くわけですが、その場合、[3]の時点で
テキストボックスには「初期値」という文字列が入っているはずなのに、なぜ
[2]の部分で「ABC」という文字列が取得できるのでしょうか。


【疑問2】
[1]の行をコメントにすると、[2]のところでエラーとなります。
(オブジェクト参照がオブジェクトインスタンスに設定されていません、となります)

正常に動作する場合の動きから考えると、ボタンを押した時点でテキストボックスの
内容がサーバーに送られていてそれがサーバー側に保存されている?ような気がするので、
[1]は無くても良いような気がするのですが、なぜエラーとなるのでしょうか。



とりあえず期待した動作はしているのですが、どうも腑に落ちません。
初歩もいいところな質問で申し訳ありませんが、よろしくお願い致します。

引用返信 編集キー/
■74802 / inTopicNo.2)  Re[1]: ASP.NETでの動的コントロールについて初歩的な質問
□投稿者/ WebSurfer (482回)-(2015/01/29(Thu) 20:28:58)
No74799 (mura さん) に返信

> 【疑問1】
> ・・・中略・・・
> [3]の時点でテキストボックスには「初期値」という文字列が入っているはずなのに、
> なぜ[2]の部分で「ABC」という文字列が取得できるのでしょうか。

Button1 クリックでポストバックされると、Page.Load イベント ⇒ TextBox.LoadViewState
メソッド ⇒ TextBox.LoadPostData メソッドという順に処理が行われ、最後の LoadPostData
メソッドでポストされた値(今回の例では "ABC")が TextBox.Text プロパティに設定される
からです。

そのあたりは以下のページが参考になると思います。

変更系イベント発生のメカニズム
http://surferonwww.info/BlogEngine/post/2010/08/03/Mechanism-of-changed-event-firing.aspx


> 【疑問2】
> ・・・中略・・・
> [1]は無くても良いような気がするのですが、なぜエラーとなるのでしょうか。

動的に生成したコントロールは、ポストバック時に自動的に生成されるわけではなく、ポスト
バックするたび生成されるようなコードを書く必要があります。

そのあたりは以下のページを参考にしてください。

[HOWTO] Visual C# .NET を使用して ASP.NET で動的にコントロールを作成する方法
http://support2.microsoft.com/default.aspx?scid=kb;ja;317794

よく勘違いされるのですが、ViewState でコントロール本体が生成されるわけではあ
りません。

ViewState には TextBox.LoadViewState メソッドで使う前の画面の情報が保持される
だけです。

引用返信 編集キー/
■74809 / inTopicNo.3)  Re[2]: ASP.NETでの動的コントロールについて初歩的な質問
□投稿者/ mura (2回)-(2015/01/30(Fri) 09:37:32)
・ボタン押下で、VIEWSTATEに、テキストボックスの名前("DynamicTextBox")と内容("ABC")が保持される
・Loadイベントが発生し、MakeTextBoxが行われたあとに、LoadViewStateメソッドが実行され、
 そのメソッドにより、MakeTextBoxで作成された"DynamicTextBox"の内容が、「初期値」から
 「ABC」に変更される
・LoadViewStateにより、"DynamicTextBox"の内容がセットされているため、[2]の部分で
 「ABC」と取り出すことができる

※[1]の処理をやらない場合
 LoadViewStateメソッドで、"DynamicTextBox"というテキストボックスに「ABC」を設定しようと
 するが、DynamicTextBoxというテキストボックスが存在しないので、なかったことになってしまう
 また、存在しないので[2]の部分で取り出すこともできない


という理解であっていますでしょうか。
LoadViewStateメソッドなど、目にみえないところで動いている部分があるということを理解
しないとだめなわけですね。

ありがとうございました。
解決済み
引用返信 編集キー/
■74811 / inTopicNo.4)  Re[3]: ASP.NETでの動的コントロールについて初歩的な質問
□投稿者/ WebSurfer (485回)-(2015/01/30(Fri) 10:59:54)
No74809 (mura さん) に返信

> ・ボタン押下で、VIEWSTATEに、テキストボックスの名前("DynamicTextBox")と内容("ABC")が保持される

「ボタン押下」というのはクライアント側のブラウザ上で Button1 をクリックした時のことを言っている
のだと思いますが、そうだとすると違います。

ASP.NET が初期画面をレンダリングする時 "初期値" を ViewState に保存し、それを隠しフィールドの
value に設定してブラウザに送信します。「ボタン押下」しても ViewState には何も起こりません。

ユーザーが TextBox に入力した "ABC" は Button1 クリックでポストバックされる時に form データと
して Web サーバーに送信されます。

その先の Web サーバーでの処置の流れは先のレスに書いたとおりです。なので、上記の次の行、

> ・Loadイベントが発生し・・・

以降に書かれた質問者さんの理解も違います。

どう違うかは先に紹介した記事「変更系イベント発生のメカニズム」をよく読んでもらえば分かると思い
ます。読んでも分からなかったらまた質問してください。


> DynamicTextBoxというテキストボックスが存在しないので、なかったことになってしまう

「なかったことになってしまう」ということではありません。

[1] のコードが無いということは、ポストパックで TextBox を生成しないということだからポストバック
時は TextBox インスタンスが存在しない。存在しない TextBox の Text プロパティには、当たり前です
が、LoadViewState メソッドでも LoadPostData メソッドでも設定しようが無いということです。


> また、存在しないので[2]の部分で取り出すこともできない

「取り出す」というのは tbx.Text で Text プロパティが取得できないと言っているのだと思いますが、
そうではないです。

ポストバック時には TextBox を生成してないのだから、その前の行の FindControl メソッドで TextBox
を取得できない、結果 tbx は null(VB.NET では Nothing)になります。

だから、tbx.Text で NullReferenceException がスローされるのです。

#質問者さんのレスから理解度を推測すると「解決済み」ではなさそうに思えますが、質問者さんご自身で
解決済みマークを付けておられるので、それを踏襲しておきます。
解決済み
引用返信 編集キー/
■74819 / inTopicNo.5)  Re[4]: ASP.NETでの動的コントロールについて初歩的な質問
□投稿者/ mura (3回)-(2015/01/30(Fri) 19:34:02)
度々申し訳ありません。

> どう違うかは先に紹介した記事「変更系イベント発生のメカニズム」をよく読んでもらえば分かると思い
> ます。読んでも分からなかったらまた質問してください。

当該記事と、下のほうにあったリンクから「ViewStateの構造」を拝見いたしました。

・初期表示の段階では、ViewStateはページを生成した状態がサーバーから送られてくるので、
 ViewState内のテキストボックスの状態には「初期値」が入ってくる
・クライアント側でクリックしてポストバックが発生すると、クライアントからはViewStateとformを
 サーバーへ送信する。ViewStateはサーバーから受け取ったそのままを送信する(「初期値」)。
 form情報には「ABC」が入っている
・サーバーでLoadViewStateメソッドが発生するが、ViewStateの内容は「初期値」なので
 「初期値」がテキストボックスにセットされる
・LoadPostDataメソッドで、テキストボックスとform情報を比較し、form情報内では「ABC」が入っているので、
 テキストボックスに「ABC」がセットされる
・その状態でページが生成されるので、ViewStateのテキストは「ABC」で送られてくる

というような理解であっていますでしょうか。
ViewStateとformの違いも理解しておらず大変恐縮です。


> [1] のコードが無いということは、ポストパックで TextBox を生成しないということだからポストバック
> 時は TextBox インスタンスが存在しない。存在しない TextBox の Text プロパティには、当たり前です
> が、LoadViewState メソッドでも LoadPostData メソッドでも設定しようが無いということです。
[1]のコードがない場合は感覚的に、LoadPostDataの時点で、「DynamicTextBoxというテキストボックスが
ありません」というエラーが発生するような感じがするのですが、これは例外とはせず、なにもしないで
終わってしまうという感じなんですね。

引用返信 編集キー/
■74823 / inTopicNo.6)  Re[5]: ASP.NETでの動的コントロールについて初歩的な質問
□投稿者/ WebSurfer (488回)-(2015/01/30(Fri) 19:58:35)
No74819 (mura さん) に返信

> ・初期表示の段階では、ViewStateはページを生成した状態がサーバーから送られてくるので、
> ・・・中略・・・
> というような理解であっていますでしょうか。

合っていると思います。

> [1]のコードがない場合は感覚的に、LoadPostDataの時点で、「DynamicTextBoxというテキストボックスが
> ありません」というエラーが発生するような感じがするのですが、これは例外とはせず、なにもしないで
> 終わってしまうという感じなんですね。

想像ですが・・・

例外をスローする必要は無いはずですし、スローすればサーバーエラーで終わってしまうので、
それでは困る場合があるという理由だと思います。

引用返信 編集キー/
■74829 / inTopicNo.7)  Re[5]: ASP.NETでの動的コントロールについて初歩的な質問
□投稿者/ WebSurfer (489回)-(2015/01/31(Sat) 10:56:32)
No74819 (mura さん) に返信

【追伸】

> ViewStateとformの違いも理解しておらず大変恐縮です。

簡単に「合っていると思います」と書いてしまいましたが、「ViewStateとformの違い」
に補足説明が必要かと思いましたので、以下に追記します。

質問者さんが作った .aspx ページが html ソースにレンダリングされると form 要素の
中身は以下のようになるはずです。

つまり、ViewState も form データの一部になります。

<form method="post" action="Default.aspx" id="form1">
  <input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="/wEPDw..." />

  ・・・中略・・・

  <input type="submit" name="Button1" value="Button" id="Button1" />
  <input name="DynamicTextBox" type="text" value="初期値" id="DynamicTextBox" />
</form>

ブラウザで TextBox(上記の <input name="DynamicTextBox" ... />)に "ABC" と入力
し Button1 をクリックすると form1 が submit されます。その際 method="post" と設
定されているので POST 要求がかかります。Web サーバーに対して以下のような要求が
送信されます。

POST http://aspnet4site/Default.aspx HTTP/1.1
・・・中略・・・
Pragma: no-cache

__VIEWSTATE=%2FwEPDw...&Button1=Button&DynamicTextBox=ABC

上記の例では、__VIEWSTATE 以降が form データです。

input 要素の name 属性と value 属性の値を = でつないで、さらにそれらを & でつな
いでいるのが分かりますか? (html ソースの value と上記の form データが異なる
のは url エンコードされるからです)

そのあたりの仕組みは「form」「データ」をキーワードにしてググると参考になるペー
ジが多々見つかると思いますので調べてみてください。

ブラウザと Web サーバーの HTTP 通信はキャプチャツール(IE の F12 開発者ツールや
Fiddler など)を利用すると中身を見ることができます。個人的には Fiddler がお勧め
です(というより開発には必須と思っています)。

引用返信 編集キー/
■74853 / inTopicNo.8)  Re[6]: ASP.NETでの動的コントロールについて初歩的な質問
□投稿者/ mura (4回)-(2015/02/02(Mon) 17:18:12)
丁寧な解説ありがとうございました。

・ViewStateはサーバーでページを生成した瞬間に作成される
・ViewStateは、サーバー側でフォームの状態を復元するための情報であり、
 クライアント側でフォームに入力したデータとは異なる
・サーバーから送信されてくるときは、form内の隠し要素としてViewStateが
 送られてくる
・クライアントから送信するときは、受け取ったViewStateそのままの内容+
 formに入力された内容を送信する

おかげさまでだいぶ理解が深まりました。

またキャプチャツールなども知りませんでしたので、使ってみたいと思います。
大変お世話になりました。
解決済み
引用返信 編集キー/


トピック内ページ移動 / << 0 >>

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -