none
ComboBox の表示データに数値を割り当てたい RRS feed

  • 質問

  • VC++6.0のアプリをC#(2005)に書き換えようとしています。

    VC++ではCComboBox::AddStringで文字列を追加した後、

    CComboBox:Tongue TiedetItemDataでその文字列に32ビット値を割り当てることができたのですが、

    C#にはSetItemDataに相当する物が見つからず困っています。

    C#のComboBoxのItems.Addは文字列以外でも追加できそうなので、Addで追加するオブジェクトを工夫すれば良いような気がするのですが、具体的な方法が見つかりません。

    どなたが助言をお願い致します。

     

    2007年6月25日 1:18

すべての返信

  • 表示する文字列とそれに対応する数値をクラスでラップし、それをItems.Addで割り当てます。以下が参考になるでしょう。

     

    Combobox Value member foreach loop
     http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=831807&SiteID=1

    2007年6月25日 2:10
    モデレータ
  • なるほど。

    DisplayMember、ValueMember、DataSource がポイントなんですね。

    何とかうまくいきました。

    注意点はDisplayMember、ValueMember、DataSourceの指定をArrayListにデータを設定してから行わないといけないようです。

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

    2007年6月26日 1:50
  • すみません、素朴な疑問があります。

     trapemiya さんからの引用
    表示する文字列とそれに対応する数値をクラスでラップし、

    わざわざラッパ クラスを作成する必要があるのでしょうか? ただの 「値 Pair」 ですよね。
    たとえば C#2.0 ならば、Generic でも良いと思いますが、何か理由があるのでしょうか?
    2007年6月26日 2:40
  •  じゃんぬねっと さんからの引用

    わざわざラッパ クラスを作成する必要があるのでしょうか? ただの 「値 Pair」 ですよね。
    たとえば C#2.0 ならば、Generic でも良いと思いますが、何か理由があるのでしょうか?

    C#1.1の頃からラッパクラスを作成してきたので、その流れでC#2.0でも同じようにやっていますが(ArrayListからGenericへは変更しています)、Genericを使うとラッパクラスを使わなくてもうまくいくのでしょうか? 逆に教えていただけないでしょうか? 

    以下、私が実際に組んでいるコードです。 (多少、省略してます)

     

        public class Kbn

        {

            private string _kbnnmn;

            private byte _kbncd;

     

            public Kbn(string strkbnnmn, byte bytekbncd)

            {

                this._kbnnmn = strkbnnmn;

                this._kbncd = bytekbncd;

            }

     

            public string Kbnnmn

            {

                get

                {

                    return _kbnnmn;

                }

            }

     

            public byte Kbncd

            {

                get

                {

                    return _kbncd;

                }

            }

        }

     

        public class Rtkbn

        {

            private List<Kbn> _arrRtkbn = new List<Kbn>();

     

            public Rtkbn()

            {

                _arrRtkbn.Add(new Kbn("ほげ~", 1));

                _arrRtkbn.Add(new Kbn("ほ~げ", 2));

            }

     

            //任意の位置に任意の項目を追加する。

            public void Usr_insertItem(int index, string strkbnnmn, byte bytekbncd)

            {

                _arrRtkbn.Insert(index, (new Kbn(strkbnnmn, bytekbncd)));

            }

     

            //任意の位置の項目を削除する。

            public void Usr_deleteItem(int index)

            {

                _arrRtkbn.RemoveAt(index);

            }

     

            public List<Kbn> ArrRtkbn

            {

                get

                {

                    return _arrRtkbn;

                }

            }

        }

    2007年6月26日 3:20
    モデレータ
  • System.Windows.Forms の ComboBox は ComboBox.DisplayMember、ValueMember なんかを使っていない場合は Item を ToString() した結果を表示しますので、値と ToString() のときに返す文字列とを設定できるクラスがあればいいような気がします。

     

    ただ、BCL にはちょうどいいクラスはなさそうです(あるのかな?)

    class ValueContainer<T>
    {
     private T value;
     private string text;
    
     public ValueContainer(T value, string text)
     {
      this.value = value;
      this.text = text;
     }
    
     public T Value
     {
      get { return this.value; }
      set { this.value = value; }
     }
    
     public string Text
     {
      get { return this.text; }
      set { this.text = value; }
     }
    
     public override string ToString()
     {
      return this.text;
     }
    }
    こんなクラスがあれば

    this.comboBox1.Items.Add(new ValueContainer<int>(1, "a"));
    this.comboBox1.Items.Add(new ValueContainer<int>(2, "b"));
    this.comboBox1.Items.Add(new ValueContainer<int>(3, "c"));
    こんな風にできます。
    

    2007年6月26日 7:17
  • キーと値のペアを DataSource に指定するならば、これではダメなのでしょうか。
    とても極端な例で申し訳ないのですが...

    C#2.0
    private void button1_Click(object sender, System.EventArgs e) {
        System.Collections.Generic.List<System.Collections.Generic.KeyValuePair<int, string>> list = (
            new System.Collections.Generic.List<System.Collections.Generic.KeyValuePair<int, string>>()
        );

       list.Add(new System.Collections.Generic.KeyValuePair<int, string>(1, "Tarou"));
        list.Add(new System.Collections.Generic.KeyValuePair<int, string>(2, "Zirou"));
        list.Add(new System.Collections.Generic.KeyValuePair<int, string>(3, "Saburo"));
        list.Add(new System.Collections.Generic.KeyValuePair<int, string>(4, "Busaikuro"));

       this.comboBox1.DisplayMember = "Value";
        this.comboBox1.ValueMember = "Key";
        this.comboBox1.DataSource = list;
    }

     
    わかりにくいので、エイリアス系のクラスを作ることはありますが、
    この程度であればラッパークラスまでは作らないことが多いです。

    私が質問の意図を取り違えているようであれば申し訳ありません。


    # ああ、ソースがきれいに表示されていない... orz
    2007年6月26日 12:10
  •  Shinichi Aoyagi さんからの引用

    System.Windows.Forms の ComboBox は ComboBox.DisplayMember、ValueMember なんかを使っていない場合は Item を ToString() した結果を表示しますので、値と ToString() のときに返す文字列とを設定できるクラスがあればいいような気がします。


    ItemをToString()した結果を表示しているのですね。勉強になりました。ただ、示されたコードの例で言うと、aを選択した際は1、bを選択した際は2などと取得するにはどのような方法があるのでしょうか?
    SelectedValueはnullでした。試しにComboBox.ValueMemberに"Value"なんて指定してみたのですが、やはりダメでした。

     

     Shinichi Aoyagi さんからの引用

    ただ、BCL にはちょうどいいクラスはなさそうです(あるのかな?)


    じゃんぬさんが示されているKeyValuePairでしょうか?

    2007年6月27日 2:01
    モデレータ
  •  じゃんぬねっと さんからの引用

    キーと値のペアを DataSource に指定するならば、これではダメなのでしょうか。
    とても極端な例で申し訳ないのですが...


    いえいえOKです。KeyValuePairですが、言われてみればどこかで見たような気がしますが、いずれにしても完全に頭にありませんでした。ありがとうございます。

    基本的にはKeyValuePairは私が示したコードにおけるKbnクラスに相当します。値ペアをcomboboxに割り当てるためにKeyValuePairというgeneric構造体でラップするか、Kbnクラスでラップするかの違いであり、考え方自体は同じです。じゃんぬさんが示されたコードをKbnクラスで書き直すと以下のようになります。

     

    List<Kbn> list = new List<Kbn>();

     

    list.Add(new Kbn("Tarou", 1));
      list.Add(new Kbn("Zirou", 2));
      list.Add(new Kbn("Saburo", 3));
      list.Add(new Kbn("Busaikuro", 4));

     

    this.comboBox1.DisplayMember = "Value";
      this.comboBox1.ValueMember = "Key";
      this.comboBox1.DataSource = list;

     

    私が兼田さんへの回答で示した参考URLにも同じ考え方が載っています。

     

     Combobox Value member foreach loop
      http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=831807&SiteID=1

     

    私が上で掲載したコードは、上のコードを使いやすいようにクラス化したものです。なぜそのようにしているかは釈迦に説法になりますが、このコンボボックスはいたるところで使用する、場合によっては最初に空白の項目を設けたいなどの理由によります。このコードを載せたのが余計話をややこしくしたかもしれませんね。すみません。

     

    結論から言えば、じゃんぬさんが言われるようにKbnというラッパークラスをわざわざ作る必要はないということですね。C#2.0ではKeyValuePairジェネリック構造体が用意されているので、それを使えということですね。

    一つかしこくなりました。ご教示、ありがとうございました。

    2007年6月27日 2:04
    モデレータ
  •  兼田 さんからの引用

    注意点はDisplayMember、ValueMember、DataSourceの指定をArrayListにデータを設定してから行わないといけないようです。

     

    参考で示したURLではArrayListを使っていますが、C#2.0ではもう使いません。そのジェネリック版のListを代わりに使って下さい。また、上でも述べていますが、C#2.0からはKeyValuePairが使えます。

    2007年6月27日 2:24
    モデレータ
  • trapemiya さん、返信ありがとうございます。

     trapemiya さんからの引用
    私が上で掲載したコードは、上のコードを使いやすいようにクラス化したものです。なぜそのようにしているかは釈迦に説法になりますが、このコンボボックスはいたるところで使用する、場合によっては最初に空白の項目を設けたいなどの理由によります。このコードを載せたのが余計話をややこしくしたかもしれませんね。すみません。

    そういうことでしたか。こちらこそ申し訳ありませんでした。
    文章にばかり着目していたので、"しなければならない" かのように受け止めてしまいました。
    (釈迦に説法だなんてとんでもないです。私なんてまだまだで... orz)

    少し触れられていらっしゃるように、ComboBox のために用意するデータの多くは、生のデータのままということは業務アプリケーションでは少ないかもしれません。

    私の場合はデータベースからマスタ データを取得してくるパターンが多いので型付 DataSet を指定しています。
    空白が必要な場合は、それ用に GetData メソッドのオーバーロードを用意して DBNull.Value で入れています。

    C#
    public HogeDataTable GetData() {}
    public HogeDataTable GetData(bool hasNullData) {}

     

    DataTable らもデータクラスの一種だと思いますが、このようにメソッドを実装することは多いにあります。
    先ほどのジェネリックを使った方法が望ましいという意図ではないということを誤解のないように書いておきます。

    何だか "クチゴタエ" みたいな感じになってしまって、申し訳ありませんでした。
    2007年6月27日 5:11
  • じゃんぬねっと さん

    > キーと値のペアを DataSource に指定するならば、これではダメなのでしょうか。

     

    KeyValuePair は思いつきませんでした。というか、

    > this.comboBox1.DisplayMember = "Value";

    > this.comboBox1.ValueMember = "Key";

    としてやればいいことを思いつきませんでした。

    なるほどです。

     

    trapemiya さん

    > ただ、示されたコードの例で言うと、aを選択した際は1、bを選択した際は2などと

    > 取得するにはどのような方法があるのでしょうか?

     

    Items に格納されていますので、キャストしてやればアクセス可能です。

      ((ValueContainer<int>)comboBox1.SelectedItem).Key

    または

      ((ValueContainer<int>)comboBox1.Items[comboBox1.SelectedIndex]).Key

    などなど。

    2007年6月28日 0:55
  •  Shinichi Aoyagi さんからの引用

    Items に格納されていますので、キャストしてやればアクセス可能です。

      ((ValueContainer<int>)comboBox1.SelectedItem).Key

    または

      ((ValueContainer<int>)comboBox1.Items[comboBox1.SelectedIndex]).Key

    などなど。

     

    そうかぁ。ComboBoxのItemにはオブジェクトが保存されているんだから、キャストしてそのオブジェクトを取り出せばいいんだ。あ~、どうして思いつかなかったんだろう。どういう風にオブジェクトが組み合って動いているかを、しっかりと把握することが基本ですね。ありがとうございました。

    2007年6月28日 1:24
    モデレータ