2013年03月02日

BindingSourceにListかList>を突っ込みたい。

こんなの調べるのに、ずいぶんかかった。。。

BindingSourceにDataRowかDictionaryを突っ込みたい。
突っ込むだけならできるのだけれど、それをDataGridViewに表示できない。
普段はDataTableに突っ込んでいるのだけれど、フィルタの機能が標準のものでは不満なのだけれど、DataRow[]だとDataGridViewで表示時に困る。
Dictionaryでも、配列でも、ちょっとめんどくさいクラスとかでもちょっと困る。
これの対応には2種類ある。
バインドするBindingSourceをどうにかするか、DataGridViewで表示するときに何とかする。
DataGridViewでやるなら「CellFormatting」「CellParse」イベントで対応できる。
実はこっちが簡単なのだけれど、画面のコントロールを何か所も直さないといけない。
正直だるい。。。

◆最終的にこんな風にやれるとうれしい。


private void Form1_Load(object sender, EventArgs e)
{
tbl = new DataTable("hoge");
tbl.Columns.Add(new DataColumn("A"));
tbl.Columns.Add(new DataColumn("B"));
tbl.Columns.Add(new DataColumn("C"));
for (int i = 0; i < 30; i++)
{
DataRow row = tbl.NewRow();
row["A"] = "A" + i;
row["B"] = "B" + i;
row["C"] = "C" + i;
tbl.Rows.Add(row);
}

// BindingSource bind = new BindingSource(); // これでなんとかなったら楽だったのに
RowsCollection bind = new RowsCollection(tbl);
for (int i = 0; i < tbl.Rows.Count; i++)
{
if (0 == i % 3)
{
bind.Add(tbl.Rows[i]);
}
}

dataGridView1.DataSource = bind;
dataGridView1.Refresh();
}



上のようにBindingSourceをつかうと、publicのプロパティー値が表示されてしまう(DataRowでいうとHasRowとか)。
違うんだ、やりたいのはテーブルをバインドした時と同じように動かしたいのだ。

いろいろ調べたけど、日本語のサイトはあまり見つからず。
DictionaryをDataGridViewにバインドって記事のほとんどは、KeyValuePairを縦に表示するような例。
いや、そんなの表示して何が嬉しいのさ。
デバックで見ればええやん。
とか思いつつ探すけれど、日本語の情報あんまりなくて。。。
数少ない参考になったのはこちら(本当に感謝!)
http://hongliang.seesaa.net/article/85853119.html

詳しくはリンク先を読んでもらえばわかるのだけれど、素直にインターフェイスをすべて実装するのは面倒臭すぎ。
お手軽にやりたいので、BindingSourceを継承して、そこにITypedListだけを実装した。
それでできたのが、こっち。



/// DataRowのコレクション
public class RowsCollection : BindingSource, ITypedList
{
#region
/// 行の情報を持つテーブル
DataTable Table { set; get; }
/// 初期化時にテーブルを保持する
public RowsCollection(DataTable target)
{
this.Table = target;
}
#endregion

#region ITypedList の明示的実装
PropertyDescriptorCollection ITypedList.GetItemProperties(PropertyDescriptor[] listAccessors)
{
DataRow row = this[0] as DataRow;
PropertyDescriptor[] props = new PropertyDescriptor[this.Table.Columns.Count];
for (int i = 0; i < props.Length; i++)
{
props[i] = new ColumnDescriptor(this.Table.Columns[i].ColumnName);
}
return new PropertyDescriptorCollection(props);
}
string ITypedList.GetListName(PropertyDescriptor[] listAccessors)
{
return string.Empty;
}
#endregion

#region Descriptor
private class ColumnDescriptor : PropertyDescriptor
{
string columnName { set; get; }
public ColumnDescriptor(string colName) : base(colName, null)
{
this.columnName = colName;
}
public override string DisplayName
{
get { return this.columnName; }
}
public override Type ComponentType
{
get { return typeof(object); }
}
public override bool IsReadOnly { get { return false; } }
public override Type PropertyType { get { return typeof(object); } }
public override bool CanResetValue(object component)
{
return false;
}
public override object GetValue(object component)
{
DataRow row = component as DataRow;
return null == row ? Convert.DBNull : row[this.columnName];
}
public override void ResetValue(object component)
{
throw new NotSupportedException();
}
public override void SetValue(object component, object value)
{
DataRow row = component as DataRow;
row[this.columnName] = value;
}
public override bool ShouldSerializeValue(object component)
{
return false;
}
}
#endregion
}



テストではかるく動かしただけなので、バグがあるかも。
DataViewにすきな行だけAddできないかとか、いろいろ調べたけれどこのコードが一番短くできそう。
Linq結果とか、配列をそのままバインドして編集できれば一番うれしかったのですがね。
数字にできるなら数字に変換してソート、それができないなら文字列にして、文字列だけでソートとかやりたいときに困るのですよ。
DataSetのSelectが、Accessみたいにfunctionを使えればこんなことをしないで済むのですがね。。。
posted by w033 at 23:53| 東京 ☀| Comment(0) | TrackBack(0) | プログラム | このブログの読者になる | 更新情報をチェックする
この記事へのコメント
コメントを書く
お名前:

メールアドレス:

ホームページアドレス:

コメント:


この記事へのトラックバック