C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[9]: カスタムクラスのArrayListをComboBox列に


(過去ログ 108 を表示中)

[トピック内 16 記事 (1 - 16 表示)]  << 0 >>

■64458 / inTopicNo.1)  カスタムクラスのArrayListをComboBox列に
  
□投稿者/ take6 (3回)-(2012/12/04(Tue) 13:26:50)

分類:[.NET 全般] 

環境:C# .NET 2.0

各レコード毎に異なるリストを持つデータを表示したいと試行錯誤しています。
そこで、DataGridViewにカスタムクラスのArrayList型のデータ(sampleList)をcomboBox列に表示しようとしています。
idとnameは表示されますが、DataGridViewComboBoxCellの例外が発生してエラーとなりリストが表示されません。

sampleListは子ウィンドウ上のリストボックスで編集が可能で削除・追加が出来るようにしていて、DataGridViewは親ウィンドウにあります。

子ウィンドウで編集した結果をcomboBoxに表示し、ソース元のsampleListも同時に編集されるようにしたいと考えています。
下記コードでデータが連結されて上手く表示されると思っていたのですが、どこに不備があるのでしょうか。。
ご教示よろしくお願いします。


データ:
<sampleHeader>
id name
123 sample01
456 sample02
<sampleList[0]>
tokyo
osaka
kyoto
<sampleList[1]>
nagoya
ishikawa

コード:
    class Data
    {
        private string _name { get; set; }
        private int _id { get; set; }
        private ArrayList _list { get; set; }

        public Data(string name, int id, ArrayList list)
        {
            _name = name;
            _id = id;
            _list = list;
        }

        public string  Name
        {
            get { return _name; }
            set { _name = value; }
        }

        public int Id
        {
            get { return _id; }
            set { _id = value; }
        }

        public ArrayList CallList
        {
            get { return _list; }
            set { _list = value; }
        }
    }

    public partial class Form1 : Form
    {

        List<SampleHeader> sampleHeader = new List<SampleHeader>();
        List<SampleData> sampleList = new List<SampleData>();

        public Form1()
        {
            InitializeComponent();

            BindingSource bs = new BindingSource();
            bs.DataSource = typeof(DataList);

            DataGridView dgv = new DataGridView();
            dgv.DataSource = bs;
            dgv.Dock = DockStyle.Fill;
            dgv.AutoGenerateColumns = false;

            List<Data> dataList = new List<Data>();

            for (int i = 0; i < sampleList.Count; ++i)
            {
                Data data = new Data(sampleHeader[i].name, sampleHeader[i].id, sampleList[i].list);
                dataList.Add(data);
            }

            bs.DataSource = dataList;

            DataGridViewTextBoxColumn columnId = new DataGridViewTextBoxColumn()
            {
                DataPropertyName = "Id",
                HeaderText = "ID",
                Name = "id",
            };

            dgv.Columns.Add(columnId);

            DataGridViewTextBoxColumn columnName = new DataGridViewTextBoxColumn()
            {
                DataPropertyName = "Name",
                HeaderText = "名前",
                Name = "name",
            };

            dgv.Columns.Add(columnName);

            DataGridViewComboBoxColumn comboBoxColumn = new DataGridViewComboBoxColumn()
            {
                DataSource = dataList,
                DataPropertyName = "CallList",
                HeaderText = "サンプルリスト",
                Name = "ComboBox",
            };

            dgv.Columns.Add(comboBoxColumn);
            this.Controls.Add(dgv);

        }

引用返信 編集キー/
■64459 / inTopicNo.2)  Re[1]: カスタムクラスのArrayListをComboBox列に
□投稿者/ プーチン (1回)-(2012/12/04(Tue) 14:15:35)
No64458 (take6 さん) に返信
> idとnameは表示されますが、DataGridViewComboBoxCellの例外が発生してエラーとなりリストが表示されません。

本当に解決したいのなら、どこでどんな例外が出るかくらい書きましょう。

引用返信 編集キー/
■64461 / inTopicNo.3)  Re[1]: カスタムクラスのArrayListをComboBox列に
□投稿者/ shu (114回)-(2012/12/04(Tue) 14:34:43)
No64458 (take6 さん) に返信

セルを取得してそのDataSourceに設定
var celcmb = (DataGridViewComboBoxCell)DataGridView1.Item[column, row];
celcmb.DataSource = 〜


文字列だけのリストなら
ArrayListではなくList<string>を使用した方がよいです。
引用返信 編集キー/
■64463 / inTopicNo.4)  Re[2]: カスタムクラスのArrayListをComboBox列に
□投稿者/ take6 (4回)-(2012/12/04(Tue) 16:29:16)
No64459 (プーチン さん) に返信
> ■No64458 (take6 さん) に返信
>>idとnameは表示されますが、DataGridViewComboBoxCellの例外が発生してエラーとなりリストが表示されません。
> 
> 本当に解決したいのなら、どこでどんな例外が出るかくらい書きましょう。
> 

値が有効ではないというエラーです。
comboBoxColumnにDisplayMember = "CallList",を追加したらエラーはなくなりましたが、
セルには(コレクション)と表示されます。
そのセル(リスト)から値を選択して他のセルを選択すると、「System.StringからSystem.Collections.Generic.List 無効なキャストです」とエラーが出ます。
そこで、ValueType = typeof(List<string>),を追加しましたが、ダメでした。

その後、CellTemplateを追加してみようと試行錯誤していますが、いまいち理解できなく。。


■No64461 (shu さん) に返信
> ■No64458 (take6 さん) に返信
> 
> セルを取得してそのDataSourceに設定
>  var celcmb = (DataGridViewComboBoxCell)DataGridView1.Item[column, row];
>  celcmb.DataSource = 〜
> 
> 
> 文字列だけのリストなら
> ArrayListではなくList<string>を使用した方がよいです。


ありがとうございます。変更しました。
まだまだ上記の問題で行き詰っています。。

引用返信 編集キー/
■64464 / inTopicNo.5)  Re[3]: カスタムクラスのArrayListをComboBox列に
□投稿者/ howling (125回)-(2012/12/04(Tue) 16:55:03)
No64463 (take6 さん) に返信

bs.DataSource = typeof(DataList);
とりあえずこんな書き方はしたことがないっす。
そもそもtypeofでいけるのか…?

http://msdn.microsoft.com/ja-jp/library/system.windows.forms.bindingsource.datasource(v=vs.80).aspx

引き続き解析してみます。VS2008でな!!(笑
自動プロパティ使えるからってのと、VS2005が無いってだけですが。
引用返信 編集キー/
■64466 / inTopicNo.6)  Re[3]: カスタムクラスのArrayListをComboBox列に
□投稿者/ shu (116回)-(2012/12/04(Tue) 17:31:29)
No64463 (take6 さん) に返信

DataSource ・・・ コンボボックスに設定するリスト
DisplayMember ・・・ コンボボックスに表示するメンバ
DataPropertyName ・・・ DataGridViewに割り当てられているデータのどの項目を該当列に割り当てるか


引用返信 編集キー/
■64468 / inTopicNo.7)  Re[2]: カスタムクラスのArrayListをComboBox列に
□投稿者/ howling (126回)-(2012/12/04(Tue) 19:27:09)
2012/12/05(Wed) 10:29:46 編集(投稿者)

削除しました。
引用返信 編集キー/
■64483 / inTopicNo.8)  Re[3]: カスタムクラスのArrayListをComboBox列に
□投稿者/ shu (117回)-(2012/12/05(Wed) 07:49:57)
No64468 (howling さん) に返信

ぱっと見ですがコンボボックス列に対する肝心の
処理がない気がしますが気のせいでしょうか?
このスレはコンボボックスに対する処理ではなくDataGridView内の
コンボボックス列に行毎に異なるリストを設定したいという内容です。
長いソースをただ記述すると問題となっている場所が
どのような処理で実装されているかわかりにくいと
思いますので長いソースを記述される場合は重要な部分が
分かるようにされるとよいかと思います。
引用返信 編集キー/
■64485 / inTopicNo.9)  Re[4]: カスタムクラスのArrayListをComboBox列に
□投稿者/ howling (127回)-(2012/12/05(Wed) 10:29:24)
No64483 (shu さん) に返信
本当だ。Comboboxcellに対してだったんですね。じゃあ間違いか…。
とりあえず間違いコードを載せておくのも何なので、一旦コメントを削除しておきます。
お騒がせしてしまってすみません。
引用返信 編集キー/
■64516 / inTopicNo.10)  Re[4]: カスタムクラスのArrayListをComboBox列に
□投稿者/ take6 (5回)-(2012/12/05(Wed) 16:18:51)
No64466 (shu さん) に返信
> ■No64463 (take6 さん) に返信
> 
> DataSource ・・・ コンボボックスに設定するリスト
> DisplayMember ・・・ コンボボックスに表示するメンバ
> DataPropertyName ・・・ DataGridViewに割り当てられているデータのどの項目を該当列に割り当てるか
> 
> 

返事が遅れてすいません。
DataGridViewから、コントロールをtableLayoutPanelに動的生成して各コントロールにデータをバインドしてみようと
試していました。
結局1日やってDataGridViewでいう1レコードの関連付けを持たせることが難しく、DataGridViewに戻ってきました。。

コンボボックス列の表示は未だ(コレクション)です。。
コンボボックス列を選択すると、WindowsFormsApplication1.Dataが2つ入っています。
2行とも同じでしたので、サンプルデータの「"tokyo"〜」のリストと「"kanaawa"〜」のリストが
コレクションとしてセルに入っているようです。

データバインドはあきらめて、Itemsで1行毎にデータを入れていくしかないのでしょうか。


現状のコードは以下です。テスト用にコンボボックス列だけにしました。

    public partial class Form1 : Form
    {
        BindingList<Data> dataList = new BindingList<Data>();
        Data data;        

        public Form1()
        {
            InitializeComponent();

            data = new Data(new List<string> { "tokyo", "osaka", "kyoto" });
            dataList.Add(data);
            data = new Data(new List<string> { "kanagawa", "nagoya", "ishikawa","ehime" });
            dataList.Add(data);

            BindingSource bs = new BindingSource();
            bs.DataSource = dataList;
 
            DataGridView dgv = new DataGridView();
            dgv.DataSource = bs;
            dgv.Dock = DockStyle.Fill;
            dgv.AutoGenerateColumns = false;

            DataGridViewComboBoxColumn comboBoxColumn = new DataGridViewComboBoxColumn()
            {
                DataSource = bs,
                DataPropertyName = "CallList",
                DisplayMember = "CallList",
                HeaderText = "サンプルリスト",
                Name = "ComboBox",
                Width=300,
            };

            dgv.Columns.Add(comboBoxColumn);
            this.Controls.Add(dgv);

        }
    }
    class Data
    {
        private List<string> _list { get; set; }

        public Data(List<string> list)
        {
            _list = list;
        }

        public List<string> CallList
        {
            get { return _list; }
            set { _list = value; }
        }
    }

引用返信 編集キー/
■64517 / inTopicNo.11)  Re[5]: カスタムクラスのArrayListをComboBox列に
□投稿者/ リサリサ (1回)-(2012/12/05(Wed) 16:34:44)
Dataクラスの構造がこれでいいのかという問題はひとまず置いといて...

例えば、

DisplayMember = "CallList",

っていうのはおかしいですよね。
"CallList"メンバの型はList<string>なので、せめてDisplayMemberにはString型のメンバを割り当てる必要があるのでは。
引用返信 編集キー/
■64518 / inTopicNo.12)  Re[5]: カスタムクラスのArrayListをComboBox列に
□投稿者/ shu (123回)-(2012/12/05(Wed) 17:05:57)
2012/12/05(Wed) 17:06:12 編集(投稿者)
No64516 (take6 さん) に返信

VB2010ですが一応それらしい動きをします。

DataGridView1には2列をデザイン時に作成し2列目をコンボボックス項目にしてあります。
AllowUserToAddRowsは処理が大変になってしまうのでとりあえずFalseにしてあります。
コンボのリストがない状態でセルに値を設定するとDataErrorイベントが発生するのを
利用して該当Cellにコンボボックス用のDataSourceを設定しています。

動的に行が増える場合はそれに合わせて処理を変更してみて下さい。

Public Class Form1
    Private m_tblList As DataTable

    Public Sub New()
        ' この呼び出しはデザイナーで必要です。
        InitializeComponent()

        ' InitializeComponent() 呼び出しの後で初期化を追加します。

     'DataGridViewにバインドするデータを作成
        m_tblList = New DataTable
        m_tblList.Columns.Add("ID", GetType(String))
        m_tblList.Columns.Add("Name", GetType(String))
        m_tblList.Columns.Add("NameList", GetType(List(Of String)))

        m_tblList.Rows.Add("1", "aaa", New List(Of String) From {"aaa", "bbb", "ccc"})
        m_tblList.Rows.Add("2", "ddd", New List(Of String) From {"ddd", "eee", "fff"})
        m_tblList.Rows.Add("3", "ggg", New List(Of String) From {"ggg", "hhh", "iii"})

        '自動列追加をオフにしてDataSourceを設定
        DataGridView1.AutoGenerateColumns = False
        DataGridView1.DataSource = m_tblList
        Column1.DataPropertyName = "ID"
        Column2.DataPropertyName = "Name"
    End Sub

    Private Sub DataGridView1_DataError(sender As Object, e As System.Windows.Forms.DataGridViewDataErrorEventArgs) Handles DataGridView1.DataError
        Select Case e.ColumnIndex
            Case 1
                Dim row = DirectCast(DataGridView1.Rows(e.RowIndex).DataBoundItem, DataRowView).Row
                Dim cell = DirectCast(DataGridView1(e.ColumnIndex, e.RowIndex), DataGridViewComboBoxCell)
                cell.DataSource = DirectCast(row("NameList"), List(Of String))
        End Select
    End Sub
End Class

引用返信 編集キー/
■64526 / inTopicNo.13)  Re[6]: カスタムクラスのArrayListをComboBox列に
□投稿者/ take6 (6回)-(2012/12/05(Wed) 18:48:43)
No64517 (リサリサ さん) に返信
> Dataクラスの構造がこれでいいのかという問題はひとまず置いといて...
> 
> 例えば、
> 
> DisplayMember = "CallList",
> 
> っていうのはおかしいですよね。
> "CallList"メンバの型はList<string>なので、せめてDisplayMemberにはString型のメンバを割り当てる必要があるのでは。

どうしてもList<string>を割り当てたいのです。ということは、Dataクラスの構造を見直さないといけないですね。
行ごとにリスト構造を順番に割り当ててくれるとイメージしていたのですが、厳しそうですね。



■No64518 (shu さん) に返信
> 2012/12/05(Wed) 17:06:12 編集(投稿者)
> 
> ■No64516 (take6 さん) に返信
> 
> VB2010ですが一応それらしい動きをします。
> 
> DataGridView1には2列をデザイン時に作成し2列目をコンボボックス項目にしてあります。
> AllowUserToAddRowsは処理が大変になってしまうのでとりあえずFalseにしてあります。
> コンボのリストがない状態でセルに値を設定するとDataErrorイベントが発生するのを
> 利用して該当Cellにコンボボックス用のDataSourceを設定しています。
> 
> 動的に行が増える場合はそれに合わせて処理を変更してみて下さい。


素晴らしい!!やりたかった処理が出来ました!
DataErrorで処理を行っているのですね。勉強になります。

VBのコードをC#に変換して動作確認できました。(参考までに下記にコードを)
これを拡張して活用して行きたいと思います。ありがとうございました!


あっ、1つだけ。
Column2を"NameList"に変えて起動し、リストから値を選択すると、
どこもクリックできなく、DataErrorでエラーを捕捉すると、
DataGridViewComboBoxCellの値が正しくないという例外が発生します。

リサリサさんの言うように、DataGridViewComboBoxColumnはstring型を指定していないと
型が合わないのでしょうか。うーん、難しい。。



    public partial class Form1 : Form
    {
       DataTable m_tblList;
 
       public Form1()
        {
            InitializeComponent();


            //DataGridViewにバインドするデータを作成
            m_tblList = new DataTable();
            m_tblList.Columns.Add("ID", typeof(string));
            m_tblList.Columns.Add("Name", typeof(string));
            m_tblList.Columns.Add("NameList", typeof(List<string>));

            m_tblList.Rows.Add("1", "aaa", new List<string> { "aaa", "bbb", "ccc" });
            m_tblList.Rows.Add("2", "ddd", new List<string> { "ddd", "eee", "fff" });
            m_tblList.Rows.Add("3", "ggg", new List<string> { "ggg", "hhh", "iii" });

            //自動列追加をオフにしてDataSourceを設定
            dataGridView1.DataError+=new DataGridViewDataErrorEventHandler(dataGridView1_DataError);
            dataGridView1.AutoGenerateColumns = false;
            dataGridView1.DataSource = m_tblList;
            Column1.DataPropertyName = "ID";
            Column2.DataPropertyName = "Name";

        }



        private void dataGridView1_DataError(object sender, System.Windows.Forms.DataGridViewDataErrorEventArgs e)
        {
            if (e.ColumnIndex == 1)
            {
                DataRow row = ((DataRowView)dataGridView1.Rows[e.RowIndex].DataBoundItem).Row;
                DataGridViewComboBoxCell cell = (DataGridViewComboBoxCell)dataGridView1[e.ColumnIndex, e.RowIndex];
                cell.DataSource = List<string>)row["NameList"];
             }
        }
    }

解決済み
引用返信 編集キー/
■64538 / inTopicNo.14)  Re[7]: カスタムクラスのArrayListをComboBox列に
□投稿者/ shu (124回)-(2012/12/06(Thu) 07:40:51)
No64526 (take6 さん) に返信
> あっ、1つだけ。
> Column2を"NameList"に変えて起動し、リストから値を選択すると、
> どこもクリックできなく、DataErrorでエラーを捕捉すると、
> DataGridViewComboBoxCellの値が正しくないという例外が発生します。
>
> リサリサさんの言うように、DataGridViewComboBoxColumnはstring型を指定していないと
> 型が合わないのでしょうか。うーん、難しい。。
これはコンボボックスのテキストボックス部分にリストを表示したいということになってしまいますが
それは無理だと思いませんか?リストをなんらかのテキスト表記にするというなら可能だと思いますが。

引用返信 編集キー/
■64539 / inTopicNo.15)  Re[8]: カスタムクラスのArrayListをComboBox列に
□投稿者/ howling (135回)-(2012/12/06(Thu) 10:20:28)
No64538 (shu さん) に返信

> これはコンボボックスのテキストボックス部分にリストを表示したいということになってしまいますが
> それは無理だと思いませんか?リストをなんらかのテキスト表記にするというなら可能だと思いますが。

これって、ToStringを自動で行って欲しいってことなんじゃないでしょうか?
例えばint値やenumを指定した場合に、数値(int値)または文字列(enumで定義したもの)が出て欲しいみたいな。
PropertyGridViewを使ってて、同じような気持ちになったことがあるので、何か良い方法があれば私もついでに知っておきたいです。
引用返信 編集キー/
■64564 / inTopicNo.16)  Re[9]: カスタムクラスのArrayListをComboBox列に
□投稿者/ shu (125回)-(2012/12/07(Fri) 11:55:30)
No64539 (howling さん) に返信
> ■No64538 (shu さん) に返信
>
>>これはコンボボックスのテキストボックス部分にリストを表示したいということになってしまいますが
>>それは無理だと思いませんか?リストをなんらかのテキスト表記にするというなら可能だと思いますが。
>
> これって、ToStringを自動で行って欲しいってことなんじゃないでしょうか?
> 例えばint値やenumを指定した場合に、数値(int値)または文字列(enumで定義したもの)が出て欲しいみたいな。
> PropertyGridViewを使ってて、同じような気持ちになったことがあるので、何か良い方法があれば私もついでに知っておきたいです。
intやenumを文字列にするのは定義済のToSTringによる結果でよいと思うのですがArrayListとかListでは
ToStringの結果というのは型名が返ってきます。これはArrayListやListに含まれる値が1つではないからです。複数の値を用いて
1つの文字列で表現するのは個々で定義するのが良いからだと思います。

それからtake6さんの提示している内容のsampleListはコンボボックスのドロップダウンリストの為のものであって
コンボボックスのテキストに表示するものではないと思います。


ArrayList AList = new ArrayList();
ComboBox1.Text = AList.ToString();


という処理を行っているのと同じような事になってしまいます。
引用返信 編集キー/


トピック内ページ移動 / << 0 >>

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -