none
findcontrolで見つけられないコントロールについて RRS feed

  • 質問

  • いつも大変お世話になっております。findcontrolでわからないことがありまして、教えていただければと思います。

     

     

    通常のfindcontrolについてはよく利用していて、『server.transfer』で振ったページからpreviouspageのコントロールを探したり、動的に作ったコントロールを探したりというのは問題なく利用しているのですが、今回、探せないコントロールがあり、スレッドを立てさせていただきました。

     

    状況としては、入力項目がその都度違うため、項目数を入力するtextboxからの数量を元にtextboxを動的に作成します。なお、表示制御用のCSSのためにいくつかのプロパティ指定がありますが、コードの間違えなどを防ぐため、実際に使用しているコードをそのまま掲載しました。

     

    rowNum = CInt(txtRows.Text)
            For I = 0 To rowNum - 1
                mPN = New Panel
                mTEXTBOX = New TextBox
                mPN.ID = "NEWPANEL"

                mPN.Attributes.Add("class", "addtextbox")
                newLiteral.Controls.Add(mPF)
                With mCITY
                    .ID = "txtNEWBOX" & I
                    .MaxLength = 10
                    .BorderWidth = 1
                    .BorderStyle = BorderStyle.Ridge
                    .Height = New Unit("1.2em")
                    .Width = New Unit("10em")
                    .BackColor = addColor
                    .CssClass = "newstyle"
                End With
                mPN.Controls.Add(mTEXTBOX)
            Next

     

    リテラルとしてPANELコントロールを使用し、位置を定義して、その中にコントロールボックスを作成しています。

     

    その後、入力データを参照するために

     

            Dim fcTEXT As TextBox = New TextBox
            Dim fctxtID As String

            For I = 0 To CInt(txtRows.Text)
                fctxtID = "txtNEWBOX" & I
                fcTEXT = CType(form1.FindControl(fctxtID), TextBox)

                処理 処理 処理
            Next

     

    としています。しかし、これでコントロールを探せる場合と探せない場合があります。

     

    いろいろ資料を見てみて、

    fcTEXT = CType(Papge.FindControl("form1").FindControl("NEWPANEL").FindControl(fctxtID), TextBox)

    なども試みましたがうまく探すことができませんでした。

     

    何かの理解不足でうまく探せていないと思うのですが、原因がよくわかりません。別のスレッドで近い内容のものでご呈示いただいている資料などがあり、それを元にいろいろ試してみましたが、そもそもC#のコードなので、正確に把握できているかも疑問があります。お手数をおかけしますが、どういった点が理解できればいいのかなどご指導賜れればと思います。どうぞよろしくお願いします。

    2007年12月1日 12:37

回答

  • えと、上記でやったことはデータを拾うプログラムの場所を変えたのではなく、TextBoxを動的に作成する部分をPage_Loadの部分に変更した、ということでいいでしょうか?
    だとすると、最初にデータを取り出せなかったのはTextBoxがまだ生成されていないタイミングなのにそれを探しにいっていたからかもしれませんね。

     

    > 私としては、行数指定ボタンを押したときではなく、その後のポストバック後にページを読み込む(HTMLをはき出す)部分にコードを移しただけでコントロールを拾えるようになったことが腑に落ちませんが…。

     

    えと、ちょっとイベントのタイミングについて誤解があるようです。

    ボタンを押すと、サーバにリクエストがあがります。

    で、このとき、まずPage_Loadが実行されます。

    その後でボタンを押した、というイベントが発生します。

    HTMLを吐き出すのはもっと後ですべてのイベントが終了してからになります。

    動的にコントロールを生成しているような場合、どのタイミングでコントロールを作っているのか、どのイベントでそのコントロールを利用するのか、といったことには十分気をつける必要があります。

     

    > ちなみに、いろいろ実験をしてみたのですが、ハードコーティングのコントロールは階層関係なしに拾えているようです。

     

    ふむ。そういえばこういった条件でfindcontrolを試したことはなかったかも。
    たいていGridViewとかで内部で生成されるコントロールを見つけるとかで使ってたので。。。

    2007年12月5日 10:34

すべての返信

  • 本題と関係ないかもしれませんが、

     

    >For I = 0 To rowNum - 1

    >For I = 0 To CInt(txtRows.Text)

    これは個数が違います。
    2007年12月1日 13:32
  • ご指摘ありがとうございます。

     

    …この問題がなければ、エラーが出る原因になっていました。早速コードの方を直しておきました。ありがとうございます。(笑)

     

    しかし、個数を合わせてもうまくいきません(当たり前ですが…)

     

    javascriptは確実に見つけられるのに、asp.net2.0は難しいものです、、、。

     

    2007年12月1日 15:32
  • 探せる場合と探せない場合の違いは何でしょうか。。。

    FindControlを使う場合、オブジェクトツリー(コントロール、およびコントロール内で作成されるオブジェクトの階層構造)を考えながら使わないとうまく取り出せないことがあるようです。

    確か自分の直下にあるコントロールしか探せなかった記憶があるのですが、、、この記憶が間違ってるかもしれませんけど。

    2007年12月3日 1:56
  • どっとねっとふぁんさま、いつもありがとうございます。実は、思いがけない方法で拾える方法が見つかりました。が、それも疑問があります。

     

    …本題の前に、今までの流れのところで少し寄り道です。

    探せる場合と探せない場合の違いはよくわからないのですが、確実にいえることは、previouspageオブジェクトからは全て拾えています。

     

    あと、いろいろ調べてみると、確かにおっしゃるとおり、オブジェクトツリーを考えながら使うのが正しいようですね。私もこの問題が出る前は、全く気にせず使っていました。なので、階層を意識して探してみたのですが、うまくいきませんでした。

     

    ところで、階層構造を考えた結果

    fcTEXT = CType(Papge.FindControl("form1").FindControl("NEWPANEL").FindControl(fctxtID), TextBox)

    と、作ってみたのですが、これはオブジェクトツリーを正しく理解できていないでしょうか?

     

    ちなみに、いろいろ実験をしてみたのですが、ハードコーティングのコントロールは階層関係なしに拾えているようです。

    もしくは、私がオブジェクトツリーを正しく理解しておらず、たまたま同階層で拾ってしまい、正しい実験になっていない可能性もありますが(汗)…。

     

    いずれにしても、今後は階層を意識しながら正しい利用法を心がけようと思います。

     

     

    ここから本題ですが、思いがけない方法というのは、

    (スレッドを立てたときのサンプル内で正しく変数宣言をしていなものなどを訂正しましたが、内容は変わっていません)

    Dim mTEXTBOX As TextBox
    Dim I As Integer
    Dim rowNum As Integer = CInt(txtRows.Text)
    For I = 0 To rowNum - 1
        mTEXTBOX = New TextBox
        With mTEXTBOX
            .ID = "txtNEWBOX" & I
            .MaxLength = 10
            .BorderWidth = 1
            .BorderStyle = BorderStyle.Ridge
            .Height = New Unit("1.2em")
            .Width = New Unit("10em")
            .BackColor = addColor
            .CssClass = "newstyle"
        End With
        phcPLACEHOLDER.Controls.Add(mTEXTBOX)
    Next

    の部分を

     

    Protected Sub DecideRowsButton_Click(ByVal sender As Object, ByVal e As System.EventArgs)

     …

    End Sub

     

    ではなく

     

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

     …

    End Sub

    の間に挟み

     

    If Page.IsPostBack Then

     …

    End If

    を付けてみました。何度もデバッグして処理を追いかけているうちにひょっとしたらと思いついた方法ですが、この使い方は正しいのでしょうか?やけというか思いつきで試してみたらたまたまできたので驚きです。むしろ、このような使い方が正しいとか???

     

    私としては、行数指定ボタンを押したときではなく、その後のポストバック後にページを読み込む(HTMLをはき出す)部分にコードを移しただけでコントロールを拾えるようになったことが腑に落ちませんが…。

    2007年12月5日 7:31
  • えと、上記でやったことはデータを拾うプログラムの場所を変えたのではなく、TextBoxを動的に作成する部分をPage_Loadの部分に変更した、ということでいいでしょうか?
    だとすると、最初にデータを取り出せなかったのはTextBoxがまだ生成されていないタイミングなのにそれを探しにいっていたからかもしれませんね。

     

    > 私としては、行数指定ボタンを押したときではなく、その後のポストバック後にページを読み込む(HTMLをはき出す)部分にコードを移しただけでコントロールを拾えるようになったことが腑に落ちませんが…。

     

    えと、ちょっとイベントのタイミングについて誤解があるようです。

    ボタンを押すと、サーバにリクエストがあがります。

    で、このとき、まずPage_Loadが実行されます。

    その後でボタンを押した、というイベントが発生します。

    HTMLを吐き出すのはもっと後ですべてのイベントが終了してからになります。

    動的にコントロールを生成しているような場合、どのタイミングでコントロールを作っているのか、どのイベントでそのコントロールを利用するのか、といったことには十分気をつける必要があります。

     

    > ちなみに、いろいろ実験をしてみたのですが、ハードコーティングのコントロールは階層関係なしに拾えているようです。

     

    ふむ。そういえばこういった条件でfindcontrolを試したことはなかったかも。
    たいていGridViewとかで内部で生成されるコントロールを見つけるとかで使ってたので。。。

    2007年12月5日 10:34
  • 今回はいろいろありがとうございます。

     

    今まで誤解していた部分がクリアになり、今後の参考になりました。

     

    ちなみに、textboxコントロールは、作成ボタンを押してから、その中身を読み込ませるときに、再度、登録実行ボタンを押すようにしてて、そのときのイベントでfindcontrolを使っていたのですが、それをPage_Loadに移してみたという経緯です。この場合も、やはり、まだ内部的にはコントロールが生成される前ということになるんでしょうか?なんだか、理解が悪くて申し訳ありません。

     

     

    >> ちなみに、いろいろ実験をしてみたのですが、ハードコーティングのコントロールは階層関係なしに拾えているようです。

    > たいていGridViewとかで内部で生成されるコントロールを見つけるとかで使ってたので。。。

     

    はい、ハードコーディングのコントロールなんて、わざわざ探さなくてもわかっているので、通常は試さない実験ですよね(汗)

     

    今回は、実験やどっとねっとふぁんさまのご助言など、大変貴重な経験になり、それだけでも良かったと感謝感謝です。

    2007年12月9日 15:44
  • イベントについて以前こちらに書いていたのを思い出しました。もし参考になれば。

     

    findControlについては、若干面倒ではありますが再帰呼び出しで検索する小さなユーティリティを用意しておくと便利です。確か、WebPartsあたりもきちんと検索できなかったりすることがあったように思います(2008を入れるため2005を消して2008を入れてないので検証環境が手元に無い罠中…)。

    2008年1月17日 4:51