none
[Winforms] ComboBoxでDataSource=nullをすると、ドロップダウンに空行が残ってしまう

    質問

  • お世話になります。

    C#・WinformsのComboBoxで教えて欲しいことがあります。

    フォーム上にComboBox(comboBox1)とButtonを2つ(button1、button2)を配置します。

    そして下記のようなコードを書きました

    /// <summary>
    /// 現在のComboBox.TextをComboBoxのドロップダウンに追加
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void button1_Click(object sender, EventArgs e)
    {
        string addtext = comboBox1.Text;
    
        if (!string.IsNullOrEmpty(addtext))
        {
            StringCollection items = null;
    
            if (comboBox1.DataSource != null &&
                comboBox1.DataSource.GetType() == typeof(StringCollection))
            {
                items = (StringCollection)comboBox1.DataSource;
            }
            else
            {
                items = new StringCollection();
            }
    
            items.Add(addtext);
    
            comboBox1.DataSource = null;
            comboBox1.DataSource = items;
            comboBox1.Text = addtext;   // バインド後、SelectedIndexの項目が選択されてしまうため
        }
    }
    /// <summary>
    /// ComboBoxをクリア
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void button2_Click(object sender, EventArgs e)
    {
        comboBox1.DataSource = null;
    }

    button1をクリックすると、現在comboBox1に入力されているテキストがcomboBox1のドロップダウンに追加される。

    button2をクリックすると、comboBox1のドロップダウンがクリアされる。

    このような処理を行っております。

    しかし、button2をクリックした時のcomboBox1のクリアで不可解な動きを見せています。

    まず、button1のクリックを使用して「aaa」「bbb」「ccc」という3つのテキストをcomboBox1のドロップダウンに追加します。

    すると下図のようになります。

    その後、button2をクリックしてみます。

    するとcomboBox1のドロップダウンはクリアされるのですが、下図のようにドロップダウンに3行分の空行が残ってしまいます。

    ドロップダウンに4つのテキストがある状態でbutton2をクリックすれば4行分の空行が、5つのテキストなら5行分の空行が残るという動きになっています。

    これを、クリア後にはドロップダウンに1行分の空行しか表示されない(これがドロップダウンに何もない時の既定の動作かと思います)という動きにしたいと思っています。

    環境は下記です。

    VS2010

    .net 4

    Win7

    ご助言などいただけたら助かります。

    よろしくお願いします。


    2012年5月30日 8:04

回答

  • 数か月前に同様の件で困ったことがあります。win7 です。

    そのときはこんなコードを書きました。

                this.DataSource = null;
                this.list.Clear();

                // ゴミ行が残る件の対処
                this.Items.Add(new object());
                this.Items.Clear();

    2012年5月30日 17:41

すべての返信

  • 以下の環境で再現しませんでした。記述されたとおりのオペレーションを試し、ドロップダウンリストが1行の空行になることを確認しました。

    • Visual Studio 2010 SP1
    • .NET Framework 4
    • Windows XP SP3

    ご参考まで。


    Blog:プログラマーな日々 http://d.hatena.ne.jp/JHashimoto/

    2012年5月30日 9:08
  • J.Hashimoto様

    情報をありがとうございます。

    こちらの環境で試した結果も掲載いたします。

    環境1

    • Windows 7 Pro SP1
    • .net framework 4(Client Profileではなくフルの方)
    • 結果・・・この現象が起きる

    環境2

    • Windows Vista Ent SP2
    • .net framework 4(Client Profileではなくフルの方)
    • 結果・・・この現象が起きる

    この現象が起きているWindowsアプリケーションは「環境1」のVisualStudio2010 Ult SP1で作った.net framework 4(Client Profileではなくフルの方)のアプリです。

    またこれと同じと思われる現象がVistaで起きてXPで起きないという情報が他のサイトからも得られました。

    http://hpcgi1.nifty.com/MADIA/vbnet/wwwlng.cgi?print+200902/09020005.txt

    これはVista以降のOSで起きる問題ということでしょうか??



    2012年5月30日 9:48
  • 数か月前に同様の件で困ったことがあります。win7 です。

    そのときはこんなコードを書きました。

                this.DataSource = null;
                this.list.Clear();

                // ゴミ行が残る件の対処
                this.Items.Add(new object());
                this.Items.Clear();

    2012年5月30日 17:41
  • galaco様

    情報をありがとうございました!

    ご助言いただいた方法で解決いたしました。

    念のためソースコード掲載しておきます。

    /// <summary>
    /// ComboBoxをクリア
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void button2_Click(object sender, EventArgs e)
    {
        comboBox1.DataSource = null;
    
        // Win7・Vistaの場合、DataSource = nullだけでは空行が残ってしまう
        // そのため、下記二行を追加している
        comboBox1.Items.Add(new object());
        comboBox1.Items.Clear();
    }

    OSによって挙動がことなるというのが少し気持ち悪いところですが、今回は簡単な対応方法がみつかりましたのでこれでクローズにしようと思います。

    もしマイクロソフトの方が見ているようでしたら、是非本件について何かご対応いただけたらありがたいです。

    2012年5月30日 23:59
  • もしマイクロソフトの方が見ているようでしたら、是非本件について何かご対応いただけたらありがたいです。

    仮に覗いていても、こちらで対応することはないと思います。確実に再現するのであれば、Connect にフィードバックされることをお勧めします。

    https://connect.microsoft.com/VisualStudio/content/content.aspx?ContentID=25941


    ひらぽん http://d.hatena.ne.jp/hilapon/

    2012年5月31日 1:07
    モデレータ
  • 補足です。

    Connect は不具合や要望を開発チームに伝えることができますが、”そのうち直るか、もしくは直らなくてもよい”というレベルの伝え方です。
    早めの対応が欲しい、Hotfix を出して欲しいレベルなら、有償サポートでお問い合わせください。

    2012年5月31日 13:13
    モデレータ
  • コンボボックスの選択肢をクリアするという目的なら、DataSource に指定しているコレクションを空にするのが筋だと思います。

    Jitta@わんくま同盟

    2012年5月31日 13:17
  • こういうことですか?

    var list = new List<string>();
    list.Add("test1");
    list.Add("test2");
    list.Add("test3");
    
    this.comboBox1.DataSource = list;
    
    list.Clear();


    2012年5月31日 13:31
  • DataSourceは初期値nullを受け入れる関係で、後からでもnullを代入してもエラーにはなりません。しかし、DataSourceのsetterを見る限り後からnullを代入されることをあまり考慮できていないように見えます。(if文で「nullだから何もしない」が選択されてしまって、情報をクリアーする処理に進まない。)

    # というのがソースコードを読んだ印象です。…のでJittaさんの指摘の方法が適切かなと。

    2012年5月31日 22:45
  • こういうことですか?

    var list = new List<string>();
    list.Add("test1");
    list.Add("test2");
    list.Add("test3");
    
    this.comboBox1.DataSource = list;
    
    list.Clear();
     「消えなかった」ということなら、BindingList<T> を使ってみてください。IBindingList インターフェイスと IList インターフェイスを比べればわかるように、IList インターフェイスにはリストまたはリストの内容が変更されたことを通知する機構がありません。


    Jitta@わんくま同盟

    2012年5月31日 23:06
  • ダメですね。
    自分が挙げたコードの List<string> をBindeingList<string> に変えてみましたが、やはり空行が残りました。

    2012年5月31日 23:55
  • ダメですね。
    自分が挙げたコードの List<string> をBindeingList<string> に変えてみましたが、やはり空行が残りました。

     言葉足らず失礼。

     「ComboBox の選択肢をクリアする」というのが目的なら、DataSource に null を代入するのではなく、設定しているコレクションをクリアするのが本来。
     List<T> だとリストの内容が変更されたことを通知しないので、Clear メソッドで“表示されている内容がクリアされない”現象が起こるかもしれません。そうであれば、BindingList<T> を使ってください。

     次のコードでは現象は発生しませんでした。

    BindingList<Class1> list;
        while (list.Count > 0)
        {
            list.RemoveAt(0);
        }
    

    Jitta@わんくま同盟

    2012年6月1日 12:51
  • 自分の「こういうことですか」以降のコードに
    >自分が挙げたコードの List<string> をBindeingList<string> に変えてみましたが

    で、Jitta さんの
    >「ComboBox の選択肢をクリアする」というのが目的なら、DataSource に null を代入するのではなく、設定しているコレクションをクリアするのが本来。
     List<T> だとリストの内容が変更されたことを通知しないので、Clear メソッドで“表示されている内容がクリアされない”現象が起こるかもしれません。そうであれば、BindingList<T> を使ってください。

    は満たしています。それでも空行が残ります。

    ちなみに Clear メソッドでなく、 RemoveAt で削除したところ空行は残りませんでした。

    2012年6月1日 13:38
  •  何度もすみません。『それでも空行が残ります。』という、今問題になっている現象ではなく、「Clear 後も、選択文字列が残ったまま」という別の状態を意図していました。

    ざっと検索したところ、connect には類似する報告がないように思いましたので登録しました。
    https://connect.microsoft.com/VisualStudio/feedback/details/746004/-combobox

    .NET Framework 4.5 で検証してくださる方、いらっしゃいますか?

    追記:kyano30さん、ありがとうございます。コメントを追加しておきました。


    Jitta@わんくま同盟


    • 編集済み Jitta 2012年6月3日 1:09
    2012年6月2日 13:27
  • VS11 Beta で .NET Framework 4.5 用に EXE 作成しました Win7 以外は仮想環境での確認です。

    .NET Framework 4.5
      Win8 CP -> 再現
      Win7    -> 再現

    .NET Framework 4.0

      Win7    -> 再現
      Vista   -> 再現
      WinXP   -> 再現せず

    .NET Framework 2.0
      Win7    -> 再現
      Vista   -> 再現
      WinXP   -> 再現せず

    XP では見た目が 全く違っていますし、どうも Framework というより OS 側の描画更新があやしい感触ですね。

    ディレクトリ選択ダイアログの問題と同様な気がします・・・・。

    ※追記

    .NET Framework 4.5 RC  (VS2012 RC)
      Win7    -> 再現

    でした。

    • 編集済み kyano30 2012年6月3日 5:24 項目追加
    2012年6月2日 15:28