none
未選択状態をRadoiButtonListで表示するには RRS feed

  • 質問

  • 毎度お世話様です。

     

    FAQだと思うのですが、上手い解が見つけられませんでした。

     

    RadioButtonListで選択した値をSQL Serverに保存してあります。

    RadioButtonListのリストがどれも選択されていない場合、該当する列にNullが格納されますが、

    これをRadioButtonListで表示しようとすると

     

    "項目一覧に存在しないため、'RadioButtonList1' に SelectedValue を指定することは無効です。
    パラメータ名: value"

    とエラーになってしまいます。

    radioButtonListは下記のように設定してあり、DBの値が1,2のときはそれぞれ"男性","女性"と

    表示されます。

     

                            <asp:RadioButtonList ID="RadioButtonList1" runat="server" OnDataBinding="RadioButtonList1_DataBinding"
                                SelectedValue='<%# Bind("性別") %>' OnDataBound="RadioButtonList1_DataBound">
                                <asp:ListItem Value="1">男性</asp:ListItem>
                                <asp:ListItem Value="2">女性</asp:ListItem>
                            </asp:RadioButtonList></td>

    DBの値がNullのときは未選択の状態でradioButtonListを表示するにはどうすればよいでしょうか。

    2008年3月2日 2:54

回答

  •  Z9M9Z さんからの引用

    1)DB上の表現としては

      0:不明 (またはNull)

      1:男性

     2:女性

    2) 画面上では男性、女性が候補としてどちらかが選択できる。両方が選択されていない場合に

      不明と解釈する

    ということを考えているのですが、CheckBoxList/RadioButtonListでは難しいでしょうか。


    RadioButtonControlに対してバインド式を使用されていますので、RadioButtonControlを何かのデータバインドコントロールの内部で使用されていると思うのですが、仮にGridViewだとすれば以下のようなコードを書けば可能です。もちろん、RadioButtonControlのSelectedValueにはバインドを割り当てないで下さい。

     

        protected void RadioButtonList1_DataBound(object sender, EventArgs e)

        {

            RadioButtonList rbt = (RadioButtonList)sender;

            GridViewRow gvr = (GridViewRow)rbt.NamingContainer;

     

            if (gvr.DataItem != null)

            {

                string strSex2 = ((DataRowView)gvr.DataItem)["sex2"].ToString();

                rbt.ClearSelection();

                ListItem lm = rbt.Items.FindByValue(strSex2);

                if (lm != null) lm.Selected = true;

            }

        }

     

        protected void GridView1_RowUpdating(object sender, GridViewUpdateEventArgs e)

        {

            e.NewValues["sex2"] = ((RadioButtonList)((GridView)sender).Rows[e.RowIndex].FindControl("RadioButtonList1")).SelectedValue;

        }


    2008年3月2日 15:10
    モデレータ

すべての返信

  •  Z9M9Z さんからの引用

    DBの値がNullのときは未選択の状態でradioButtonListを表示するにはどうすればよいでしょうか。

     

    直接データバインドしている状態では無理ですので、コードで処理する必要があります。しかし、それを実現したとして、疑問が残ります。それは、性別が男性でも女性でもないデータが存在しているということです。このデータは不明を表していると思うのですが、もし不明という状態を表しているのであれば、nullではなく、きちんとコード体系として加え、ユーザーが不明を選択できるようにすべきです。例えば、以下のようにです。

    0:不明、1:男性、2:女性

    なぜなら、もし、男性と女性しかなければ、ユーザーは一度誤って男性もしくは女性を選択してしまうと、どちらにもチェックしていない状態である不明にすることができません。

     

    もし、不明を追加するのであれば、この件はこれで解決します。

    2008年3月2日 6:10
    モデレータ
  •  trapemiya さんからの引用
     Z9M9Z さんからの引用

    DBの値がNullのときは未選択の状態でradioButtonListを表示するにはどうすればよいでしょうか。

    例えば、以下のようにです。

    0:不明、1:男性、2:女性

     

    これで0:不明を非表示にできませんか。ItemListをEnabledプロパティをFalseにすると選択不可の状態で

    表示されてしまうのでできれば表示しないでおきたいです。

     

     

    2008年3月2日 7:39
  •  trapemiya さんからの引用
     Z9M9Z さんからの引用

    DBの値がNullのときは未選択の状態でradioButtonListを表示するにはどうすればよいでしょうか。

    それは、性別が男性でも女性でもないデータが存在しているということです。このデータは不明を表していると思うのですが、もし不明という状態を表しているのであれば、nullではなく、きちんとコード体系として加え、ユーザーが不明を選択できるようにすべきです。

     

    データの表現としてはその通りだと思いますが、RadioButtonLIstの働きからすると、

    1) 何も選択されていない

    2) どれか一つのエントリが選択されている

    のどちらかの状態があって、1)の場合がデフォルトではnullにマッピングされているようですので、

    nullの場合は1)に戻してくれてもいいんじゃないかな、と思った次第です。

    2008年3月2日 7:53
  •  Z9M9Z さんからの引用

    1) 何も選択されていない

    2) どれか一つのエントリが選択されている

    のどちらかの状態があって、1)の場合がデフォルトではnullにマッピングされているようですので、

    nullの場合は1)に戻してくれてもいいんじゃないかな、と思った次第です。


    新規登録時の話であれば、nullにマッピングされているわけでありません。新規登録しようとしているのですから、どのレコードとも結びついていません。バインドには方向があって、レコードから値を表示する方向と、レコードへ値を書き出す方向の2種類があります。新規登録時には前者はあり得ません。後者の場合にRadioButtonListで何も選択されていなければ、結果としてnullがレコードに書かれているだけです。
    その後、このレコードを表示する際に前者のバインドが発生しますが、nullはRadioButtonListの項目リストにないためバインドに失敗します。

     

    バインドに対応するためには、書き出す方向のバインドと読み出す方向のバインドが成功しなければなりません。したがって、書き出す際にnllを許さないか、読み出す際にnullに対応した項目を用意するかのどちらかです。
    今回のケースは、書き出す際にnullを許すが、読み出す際にはnullを許さない(nullに対応した項目がない)というのが問題なのです。もし、書き出す際にnullを許し、読み出す際にもnullを許す仕様であった場合、問題なくRadioButtonListはどれも選択されていない状態で表示されるでしょう。しかし、くどいですが、このRadioButtonListで一度でもどれかを選択した場合、二度とnullとしてレコードに書き出させなくなります。なぜなら、どれも選択しないという状態をユーザーの操作では作り出せないからです。nullを許しているということは、ユーザーがnullを選択できなければ一般的にはおかしいのです。新規登録時にのみユーザーはnullを選択できるというのは一般的におかしいのです。当然、オペミスはありますから。
    このようなわけでバインドした際には必ず一致する項目がなければならないという仕様になっているのだと思います。

     

    以上は、バインドした際における仕様です。ですので、バインドしなければ、レコードの値がnullであった場合、RadioButtonListはどれも選択していない状態にすることは、コードで行えば可能です。しかし、依然としてユーザーが更新時にnullを選択できなくなってしまう問題が残ります。じゃぁ、RadioButtonListで何も選択していない状態にするボタンでも追加すればいいんじゃない?と思われるかもしれません。でも、これなら、私は男性か女性かわからない場合のために、不明という項目を追加した方がいいんじゃないかと思うのです。

     

    #以上、私の考えですので、いや、こんな場合にこうした方がいいというのがあれば、教えて下さい。考えます。

    2008年3月2日 10:31
    モデレータ
  •  

    trapemiya さん、お付き合いいただいてありがとうございます。

     

    個人的には初期段階で何も選択していないものをnullとして書き込むなら、読み出し時にnullを

    無選択状態として欲しかったですね。今ちょっとためしただけですが、CheckBoxListでも同様に

    全てのチェックがされていない場合はnullが書き込まれるのにnullを読みだそうとすると同様の

    エラーになります。

     

    CheckBoxListならどれも選択されていない状態はあり得るはずなのでこちらでSelectedな状態を

    0または1個しかないように制限すればうまくいくかと思ったのですが...

     

    やりたいことを整理してみました。

    1)DB上の表現としては

      0:不明 (またはNull)

      1:男性

     2:女性

    2) 画面上では男性、女性が候補としてどちらかが選択できる。両方が選択されていない場合に

      不明と解釈する

    ということを考えているのですが、CheckBoxList/RadioButtonListでは難しいでしょうか。

    2008年3月2日 13:58
  •  

    ちょっと進展しました。

    今までBindをSelectedValueに対して行っていたので未選択時にNullになっていたのですが、

    SelectedValueにBindすることで未選択時に-1が設定されることに気が付きました。

     

    ですので、

    DB上

    -1:未選択

    0:男性

    1:女性

     

    であれば画面上男性と女性のチェックだけ出す、ということが可能になりました。

     

    2008年3月2日 14:41
  •  Z9M9Z さんからの引用

    1)DB上の表現としては

      0:不明 (またはNull)

      1:男性

     2:女性

    2) 画面上では男性、女性が候補としてどちらかが選択できる。両方が選択されていない場合に

      不明と解釈する

    ということを考えているのですが、CheckBoxList/RadioButtonListでは難しいでしょうか。


    RadioButtonControlに対してバインド式を使用されていますので、RadioButtonControlを何かのデータバインドコントロールの内部で使用されていると思うのですが、仮にGridViewだとすれば以下のようなコードを書けば可能です。もちろん、RadioButtonControlのSelectedValueにはバインドを割り当てないで下さい。

     

        protected void RadioButtonList1_DataBound(object sender, EventArgs e)

        {

            RadioButtonList rbt = (RadioButtonList)sender;

            GridViewRow gvr = (GridViewRow)rbt.NamingContainer;

     

            if (gvr.DataItem != null)

            {

                string strSex2 = ((DataRowView)gvr.DataItem)["sex2"].ToString();

                rbt.ClearSelection();

                ListItem lm = rbt.Items.FindByValue(strSex2);

                if (lm != null) lm.Selected = true;

            }

        }

     

        protected void GridView1_RowUpdating(object sender, GridViewUpdateEventArgs e)

        {

            e.NewValues["sex2"] = ((RadioButtonList)((GridView)sender).Rows[e.RowIndex].FindControl("RadioButtonList1")).SelectedValue;

        }


    2008年3月2日 15:10
    モデレータ
  •  Z9M9Z さんからの引用

    今までBindをSelectedValueに対して行っていたので未選択時にNullになっていたのですが、

    SelectedValueにBindすることで未選択時に-1が設定されることに気が付きました。

     

    ですので、

    DB上

    -1:未選択

    0:男性

    1:女性

     

    であれば画面上男性と女性のチェックだけ出す、ということが可能になりました。

     

    SelectedIndexの間違いですよね?

    おっしゃられる通り、SelectedIndexは選択されていない時に-1になりますので、-1はRadioButtonListのSelectedIndexにとって常に有効な値です。そのためにうまく動いています。発想の転換で、RadioButtonListなどでうまく動くように性別のコード体系を決めるのもいいかもしれません。人間が見ても、-1,0,1のコード体系はおかしなものではないですし。ただし、トリッキーで特殊であることは否めず、どうしてもプログラムがわかりにくくなると思いますので、できるだけこのようなことを行わないほうが無難だと思います。

    プログラムがシンプルである代わりに特殊なことをするよりも、プログラム量が多少多くになっても考え方が素直な方を私は好みます。それは将来の保守性を考えるからです。
    2008年3月2日 15:26
    モデレータ
  •  trapemiya さんからの引用
     

    SelectedIndexの間違いですよね?

    おっしゃられる通り、SelectedIndexは選択されていない時に-1になりますので、-1はRadioButtonListのSelectedIndexにとって常に有効な値です。そのためにうまく動いています。発想の転換で、RadioButtonListなどでうまく動くように性別のコード体系を決めるのもいいかもしれません。人間が見ても、-1,0,1のコード体系はおかしなものではないですし。ただし、トリッキーで特殊であることは否めず、どうしてもプログラムがわかりにくくなると思いますので、できるだけこのようなことを行わないほうが無難だと思います。

    プログラムがシンプルである代わりに特殊なことをするよりも、プログラム量が多少多くになっても考え方が素直な方を私は好みます。それは将来の保守性を考えるからです。

     

    ご指摘の通り、SelectedIndexです。

     

    確かにツール側の採番の都合にデータの構造を合わせるのはできれば避けたいのでtrapemiyaさんがご提案くださった

    方法も含めてもう少し考えていきます。

     

    いくつか案をいただけたのでこれでこちらは閉じたいと思います。

    ありがとうございました。

    2008年3月2日 15:49