none
複数のComboBoxで同じオブジェクトを参照して利用したい RRS feed

  • 質問

  • C# 2017
    .NET Framework 4.5
    WinForms

    困っている課題があり、他の質問でアドバイスをもらいましたが、よくわからず具体的なコードで教えていただいたいと思います。

    アドバイスをもらい、困っていることをシンプルに考えた時、表題の通りとなります。
    DataSourceを利用して、comboBox1は全データを常に保有し、comboBox2では一部のデータを保有して表現を可能としたいというところになります。
    データは、DataTableオブジェクトとします。
    ここで、comboBox2で選択したオブジェクト(DataRow)を比較した時、comboBox1に紐づいている全データのオブジェクト(DataRow)のいずれかと合致する、という形を取りたいです。

    comboBox2の方ではToList()、ToArray()などでDataSouce を設定してみましたが、DisplayMember、ValueMemberが正しく動作しなくなります。
    やり方がよく分かっていないため正解が分からず、comboBox2のDataSource をどうやって設定すればいいか分かりません。
    どう書けばいいのでしょうか?
    現在試したコードは以下の通りになります。

        public partial class Form1 : Form
        {
            public Form1()
            {
                InitializeComponent();
            }
    
            private DataTable dataTable;
    
            // 全体のデータを有するコンボボックス(comboBox1)を用意
            private void Form1_Load(object sender, EventArgs e)
            {
                this.CreateDataSource();
    
                comboBox1.DataSource = this.dataTable;
                comboBox1.DisplayMember = "Column1";
                comboBox1.ValueMember = "Column2";
            }
    
            private DataTable CreateDataSource()
            {
                this.dataTable = new DataTable();
                this.dataTable.Columns.Add("Column1");
                this.dataTable.Columns.Add("Column2");
    
                var r = this.dataTable.NewRow();
                r["Column1"] = "aaa1";
                r["Column2"] = "aaa2";
                this.dataTable.Rows.Add(r);
    
                r = this.dataTable.NewRow();
                r["Column1"] = "bbb1";
                r["Column2"] = "bbb2";
                this.dataTable.Rows.Add(r);
    
                r = this.dataTable.NewRow();
                r["Column1"] = "ccc1";
                r["Column2"] = "ccc2";
                this.dataTable.Rows.Add(r);
    
                r = this.dataTable.NewRow();
                r["Column1"] = "ddd1";
                r["Column2"] = "ddd2";
                this.dataTable.Rows.Add(r);
    
                r = this.dataTable.NewRow();
                r["Column1"] = "eee1";
                r["Column2"] = "eee2";
                this.dataTable.Rows.Add(r);
    
                return this.dataTable;
            }
    
            // 一部のデータを有するコンボボックス(comboBox2)を用意
            private void button1_Click(object sender, EventArgs e)
            {
                var data = this.GetPartRow().ToList();
                comboBox2.DataSource = data;
                comboBox2.DisplayMember = "Column1";
                comboBox2.ValueMember = "Column2";
            }
    
            public IEnumerable<DataRow> GetPartRow()
            {
                foreach (var row in this.dataTable.AsEnumerable())
                {
                    // aaa1は対象外にする
                    if (row["Column1"].ToString() == "aaa1")
                    {
                        continue;
                    }
                    yield return row;
                }
            }
    
            // comboBox2で選択されているオブジェクトが、comboBox1に含まれるオブジェクトのどれかと合致するかを確認
            private void button2_Click(object sender, EventArgs e)
            {
                foreach (var row in this.dataTable.AsEnumerable())
                {
                    if (row == comboBox2.SelectedItem)
                    {
                        Console.WriteLine("おなじ!:" + row["Column1"].ToString());
                    }
                }
                
            }
        }


    2018年11月26日 9:26

回答

  • アプローチはいろいろあると思いますが、例えばDataViewクラスを使うことで元のDataTableに対して見せ方(フィルターやソート)を変えることができます。

    comboBox2.DataSource = new DataView(dataTable) { RowFilter = "Column1<>'aaa1'" };
    comboBox2.DisplayMember = "Column1";
    comboBox2.ValueMember = "Column2";

    • 回答としてマーク takiru 2018年11月27日 8:28
    2018年11月26日 10:02

すべての返信

  • アプローチはいろいろあると思いますが、例えばDataViewクラスを使うことで元のDataTableに対して見せ方(フィルターやソート)を変えることができます。

    comboBox2.DataSource = new DataView(dataTable) { RowFilter = "Column1<>'aaa1'" };
    comboBox2.DisplayMember = "Column1";
    comboBox2.ValueMember = "Column2";

    • 回答としてマーク takiru 2018年11月27日 8:28
    2018年11月26日 10:02
  • 回答ありがとうございます。

    DataViewの検討は、CompareInfoおよびCompareOptionsを利用して条件を絞り込みたく、正直ムリかなと思っていたのですが、教えていただいた後に調べて、以下ページの方法を見つけてそれっぽくできました!
    https://docs.microsoft.com/ja-jp/dotnet/framework/data/adonet/filtering-with-dataview-linq-to-dataset

                var ci = CultureInfo.CurrentCulture.CompareInfo;
    
                EnumerableRowCollection<DataRow> query = from order in dataTable.AsEnumerable()
                                                         where order["Column1"].ToString() != "aaa1" &&
                                                         ci.IndexOf(order["Column1"].ToString(), "A", CompareOptions.IgnoreCase) > -1
                                                         select order;
                
                var data = query.AsDataView();
                comboBox2.DataSource = data;
                comboBox2.DisplayMember = "Column1";
                comboBox2.ValueMember = "Column2";

    これよりいい方法があるようでしたら教えていただけたら幸いです。

    2018年11月26日 11:09