none
DetailsViewへの値の設定 初期値セット RRS feed

  • 質問

  • こんにちわ、ASP.net(VB.net)とSQLserverでマスタメンテ画面を作成し始めた初心者です。

    件名のようにDetailsViewに初期値を入れておき、入力の手間を省くようにしたいので

    下記のような記述をインターネットで見つけたので自分用に項目名のみ変えて追加しました。

    DetailsView1を設置した新規登録画面に遷移したときのページロードのコードです。

       Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
            Label2.Text = Session("bumon")

     Dim tb As TextBox

      tb = CType(DetailsView1.FindControl("部門コード"), TextBox)
      tb.Text = Session("bumon")
         tb.Enabled = False

        End Sub

    ですが、

    NullReferenceException オブジェクト参照がオブジェクト インスタンスに設定されていません。

    のエラーが表示されてうまくいきません。デバッグモードで確認したところtbがnothingでした。

    うまくキャストできてないような感じですが、これ以上は一人で考えても解らなくなってきたので質問しました。

    【解っていること】

    ・DetailsViewで追加、更新、削除は可能

    ・SQLserverの項目名は「部門コード」

    ・Label2.Text = Session("bumon")でログイン時の部門コードを表示できている

    ・デバッグモードで確認したところtbがnothing

    情報が足りないかもしれませんが、すみませんが解る方いましたら、御教授くださいませ。


    2012年8月13日 9:37

回答

  • IDは自動的に作成されますが、自動的に作成されたIDを見つけて使用するよりも、自分で明にIDを指定し、それを利用すると良いでしょう。それにはまず、その列をテンプレート列に変換します。
    テンプレート列に変換するには、DetailsViewの右上に表示される「>」をクリックし、「フィールドの編集」をクリックして「フィールド」の画面を出します。
    「選択されたフィールド」からテンプレートに変換したい列をクリックして選び、「このフィールドをTemplateFieldに変換します」をクリックし、テンプレート列に変換します。その後、OKボタンを押して「フィールド」画面を閉じます。
    ふたたび、DetailsViewの右上に表示される「>」をクリックし、今度は「テンプレートの編集」をクリックします。DetailsViewがテンプレート編集モードで開きますので、テンプレート列に変換した列の表示名でInsertItemTemplateを選びます。(もし、表示名を選ぶ画面が出ていない場合は、DetailsViewの右上に表示される「>」をクリックして下さい)
    InsertItemTemplate内にTextBoxが表示されます。このTextBoxが新規登録時に表示されます。このTextBoxのプロパティでIDを指定します。これで、TextBoxのIDを明に指定することができました。

    DetailsViewでFindControlするのはDataBoundイベントで行います。Page.Loadのタイミングではまだ完全にDetailsViewの準備が完了していません。コード例を以下に示します。IDはとりあえずTextBox1にしています。

    Protected Sub DetailsView1_DataBound(sender As Object, e As EventArgs) Handles DetailsView1.DataBound
    
        If DetailsView1.CurrentMode = DetailsViewMode.Insert Then
            Dim tb As TextBox
    
            tb = CType(DetailsView1.FindControl("TextBox1"), TextBox)
            tb.Text = Session("bumon")
            tb.Enabled = False
        End If
    
    End Sub


    ★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://d.hatena.ne.jp/trapemiya/

    • 回答としてマーク kureyon77777 2012年8月14日 6:46
    2012年8月14日 2:28
    モデレータ

すべての返信

  • FindControl の意味が分かってますか?

    Page.Load のタイミングで、id が「部門コード」という TextBox が
    あるのでしょうか?

    なければ見つからないので Nothing になるのは当然ですが。

    2012年8月13日 10:14
  • 早速の返信ありがとうございます!

    SurferOnWwwさんの御回答で私がわからないことが2つあります。

    1.DetailsView1は

    Page.Loadのタイミングで作成されている⇒「部門コード」という TextBox ができている

    と思っているのですが間違っていますでしょうか?それともIDが間違っているのでしょうか?

    2.DetailsViewのInsertモード時、DetailsViewの各項目のTextBoxのIDはどのように調べれば解りますか?

    すみませんがよろしくお願い致します。

    2012年8月14日 0:31
  • IDは自動的に作成されますが、自動的に作成されたIDを見つけて使用するよりも、自分で明にIDを指定し、それを利用すると良いでしょう。それにはまず、その列をテンプレート列に変換します。
    テンプレート列に変換するには、DetailsViewの右上に表示される「>」をクリックし、「フィールドの編集」をクリックして「フィールド」の画面を出します。
    「選択されたフィールド」からテンプレートに変換したい列をクリックして選び、「このフィールドをTemplateFieldに変換します」をクリックし、テンプレート列に変換します。その後、OKボタンを押して「フィールド」画面を閉じます。
    ふたたび、DetailsViewの右上に表示される「>」をクリックし、今度は「テンプレートの編集」をクリックします。DetailsViewがテンプレート編集モードで開きますので、テンプレート列に変換した列の表示名でInsertItemTemplateを選びます。(もし、表示名を選ぶ画面が出ていない場合は、DetailsViewの右上に表示される「>」をクリックして下さい)
    InsertItemTemplate内にTextBoxが表示されます。このTextBoxが新規登録時に表示されます。このTextBoxのプロパティでIDを指定します。これで、TextBoxのIDを明に指定することができました。

    DetailsViewでFindControlするのはDataBoundイベントで行います。Page.Loadのタイミングではまだ完全にDetailsViewの準備が完了していません。コード例を以下に示します。IDはとりあえずTextBox1にしています。

    Protected Sub DetailsView1_DataBound(sender As Object, e As EventArgs) Handles DetailsView1.DataBound
    
        If DetailsView1.CurrentMode = DetailsViewMode.Insert Then
            Dim tb As TextBox
    
            tb = CType(DetailsView1.FindControl("TextBox1"), TextBox)
            tb.Text = Session("bumon")
            tb.Enabled = False
        End If
    
    End Sub


    ★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://d.hatena.ne.jp/trapemiya/

    • 回答としてマーク kureyon77777 2012年8月14日 6:46
    2012年8月14日 2:28
    モデレータ
  • trapemiyaさん

    御回答ありがとう御座います。

    テンプレート化して明示的に項目名をつけてDataBoundイベントで行うと出来ました!

    手順もわかりやすく書いてあり非常に助かりました。

    ありがとう御座いました!

    2012年8月14日 6:50
  • 揚げ足を取っているわけではなくて、正確に書きたいという意図の
    みですので、ご了承ください。

    > IDは自動的に作成されますが、自動的に作成されたIDを見つけて使
    > 用するよりも、自分で明にIDを指定し、それを利用すると良いでし
    > ょう。それにはまず、その列をテンプレート列に変換します。

    BoundField を使った場合、自動的に生成される Label や TextBox
    に ID は付与されません(null になります)。

    MSDN ライブラリに "このプロパティが宣言によってもプログラムに
    よってもサーバー コントロールに指定されていない場合は、親コン
    トロールの Controls プロパティを通じてコントロールへの参照を
    取得できます。"  と書いてあるように、FindControl を使用しなく
    ても TextBox への参照は取得可能です。

    また、TextBox が生成されるのは DetailsView.ItemCreated イベン
    トのタイミングのようです。DataBound イベントは、ポストバックし
    て ViewState からデータを取得できる場合は発生しないことがあり
    ますので、要注意と思います。

    2012年8月14日 14:18
  • 揚げ足を取っているわけではなくて、正確に書きたいという意図の
    みですので、ご了承ください。

    忌憚なくどんどんお願いします。

    BoundField を使った場合、自動的に生成される Label や TextBox
    に ID は付与されません(null になります)。

    テストコードを書いてみて、自動的にIDが降られていることを確認したのですが、いろいろ調べていくうちに、ClientIDを参照した後だとIDが入っていました。それまではnothingでした。
    ClientIDの決定にはIDが必要なようですので、そのタイミングでIDが降られ、たまたま私はそのタイミングでIDを見てしまったようです。

    Control.ClientID プロパティ
    http://msdn.microsoft.com/ja-jp/library/system.web.ui.control.clientid

    また、TextBox が生成されるのは DetailsView.ItemCreated イベン
    トのタイミングのようです。DataBound イベントは、ポストバックし
    て ViewState からデータを取得できる場合は発生しないことがあり
    ますので、要注意と思います。

    今回はTextBoxへの値の設定ですから、おっしゃる通りTextBoxが生成された後に発生するItemCreatedイベントが適切なような気がしますね。
    私がDataBoundイベントを選んだ理由は、ItemCreatedイベントハンドラではTextBoxなどのコントロールは生成済みなので取得できますが、そのコントロールのTextプロパティなどの値がまだ取れず、DataBoundイベントハンドラでは取れるため、DataBoundイベントを使うケースが多く、深く考えずにその流れでDataBoundイベントを選んでしまいました。確かにViewStateによって2回目以降はDataBoundイベントが発生しない場合がありますから、注意が必要な場合がありますね。この点については気が付いていませんでした。ご指摘ありがとうございました。


    ★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://d.hatena.ne.jp/trapemiya/

    2012年8月15日 2:10
    モデレータ