コンボボックスのDataSourceプロパティの使い方

コンボボックスに表示するデータを設定するのを簡単にする工夫をまとめます。コンボボックスのDataSourceプロパティを上手に使いましょう。(2017/8/30追記)


たとえば、英語のテストの成績で検索するソフトを作るとします。コンボボックスで「優」を選ぶと、「[英語]>=80」という条件でテーブルを検索したりする。


この画面のコンボボックスを作るときに便利なのがDataSourceプロパティを使う方法。

まず、タイトルとSQL式を記憶するクラスを定義する。

  1.         class nn検索条件
  2.         {
  3.             public string Title { get;  set; }
  4.             public string Sql { get;  set; }
  5.         }
  6.  
続いて、タイトルとSQL式をペアにしたリストを作る。たとえば「不可」は60点未満という具合。

  1.         List<nn検索条件> lst検索条件 = new List<nn検索条件>()
  2.         {
  3.             new nn検索条件() { Title = "全員", Sql = "1=1" },
  4.             new nn検索条件() { Title = "優", Sql = "[英語] >= 90" },
  5.             new nn検索条件() { Title = "良", Sql = "[英語] between 70 and 89" },
  6.             new nn検索条件() { Title = "可", Sql = "[英語] between 60 and 69" },
  7.             new nn検索条件() { Title = "不可", Sql = "[英語] < 60" },
  8.         };
  9.  
コンボボックスは、以下のように設定する。まずDataSourceに上記のリストを設定して、DisplayMemberに表示するデータのプロパティ名(ここではTitle)、ValueMemberはコンボボックスの各項目に割り当てる値のプロパティ名(ここではSql)を指定する。

  1.             this.comboBox1.DropDownStyle = ComboBoxStyle.DropDownList;
  2.             this.comboBox1.DisplayMember = "Title";
  3.             this.comboBox1.ValueMember = "Sql";
  4.             this.comboBox1.DataSource = lst検索条件;
  5.             this.comboBox1.SelectedIndex = 0;

こうしておくと、コンボボックスにタイトルの一覧が表示され、なにかを選ぶとSelectedIndexChanged イベントでSQL式を簡単にゲットできるようになる。とても便利。

  1.         private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
  2.         {
  3.             string sql = this.comboBox1.SelectedValue.ToString();
  4.             this.labelSql.Text = sql;
  5.         }
(末尾にイベントの注意点を追記したので参照されたい)



ここで注意点。

クラスを定義するとき、メンバーはpublicなプロパティでなければならない。たとえば、下のように普通のメンバー変数なのはダメ。
  1.         class bad検索条件
  2.         {
  3.             public string Title;
  4.             public string Sql;
  5.         }
  6.  

プロパティにするのを忘れると、コンボボックスの表示がおかしくなる。値もうまくゲットできない。



DictinaryをDataSourceに設定する

(追記)2017/7/8

コンボボックスに表示するためだけにクラスを作るのが面倒であるなら、Dictionaryを使う方法もある。扱うデータが表示するテキストとそれに対応したデータ1個だけなら、これが簡単。

  1.         Dictionary<string, string> di検索条件 = new Dictionary<string, string>()
  2.         {
  3.             { ”全員”,  "1=1" },
  4.             { ”優”,  "[英語] >= 90" },
  5.             // 中略
  6.         };

コンボボックスでは、DisplayMemnerプロパティは「Key」を、ValueMemberプロパティは「Value」を指定すればよい。ただDictionaryオブジェクトはDataSourceに設定できないので、ToList()でListオブジェクトに変換が必要。

  1.             this.comboText.DisplayMember = "Key";
  2.             this.comboText.ValueMember = "Value";
  3.             this.comboText.DataSource = diOps.ToList();
  4.             this.comboText.SelectedIndex = 0;

すっきりしてよい感じかも。

SelectedIndexChangedイベントのエラーを避けるには

(追記)2017/8/30

DataSourceプロパティに値を設定すると、コンボボックスのSelectedIndexChangedイベントが発生する。たとえば5個のリストを設定すると、5回イベントが発生する。

このタイミングで発生されると、まだ準備ができていないので、結構な割合で実行時エラーになってしまう。非常に面倒くさい。

これまではフラグを立てて、その間はイベント内の処理は実行しないと云う感じでしのいでいたのだが、もっと良い方法があった。

SelectionChangeCommitted イベントは、ユーザーが選択したときだけ発生するという実にありがたいイベントで、これを使えば上記の面倒なことから解放される。すべて解決。

マイクロソフトのヘルプには(MSDN)、
SelectionChangeCommitted は、ユーザーがコンボ ボックスの選択項目を変更したときにのみ発生します。SelectedIndexChanged イベントと SelectedValueChanged イベントは、プログラム上で選択項目が変更されたときにも発生するため、ユーザーによる変更をキャプチャする目的でこれらのイベントを使用しないでください。
とあって、SelectedIndexChangedはユーザーによる変更を見たいときは使ってはいけないらしい。なんと、、、ずっと使い方を間違っていたのであった。

コメント

このブログの人気の投稿

varchar をデータ型 numeric に変換中に、算術オーバーフロー エラーが発生しました。