さて、前回の続き。
DataGridとDataTableは非常に相性がよいのですが、「AutoGenerateColumn=”True”」で使う際困った問題があります。
例えば、前回のソースコードを、次のように変更してみます。
var table = new DataTable(); table.Columns.Add("Column1"); table.Columns.Add("Column.2"); table.Columns.Add("Column3"); table.Columns.Add("Column4"); for (int i = 0; i < 20; i++) { var row = table.NewRow(); for (int j = 0; j < table.Columns.Count; j++) { row[j] = "[" + (i + 1) + "," + (j + 1) + "]"; } table.Rows.Add(row); } this.DataContext = table;
違いは、Column名に「.」が入ったこと。そうすると
あら不思議。表示されなくなりました。
これは各方面で報告されている(例えば、ココとかココとか)通り で、WPFのBindingPathの解決の仕組みとColumn名がバッティングしているためです。
回避方法として、提案されているのは
- Unicodeで似ている文字を使う
- BindingPathを”[ ]”で括る
です。Unicodeで似ている文字を使うのは論外として、”[ ]”で括るのは、このケースにおいては、一見うまくいっているように見えます。しかし、WPFのBindingPathの予約文字と被ったってことは、考慮しないといけないのは”.”だけではないことは容易に想像できますね。例えば、”[“とかがColumn名に含まれると非常にまずいわけです。(この場合は問答無用で例外が発生します。)
つまり、ClassのProperty名と違って使用不可文字のないDataColumn.ColumnNameを使用してBindingPathとすることはそもそも無理があるということになります。
ひとまず、自分の回避策を載せておきますが、どうするのが正解かはわかっていません。
var table = new DataTable(); table.Columns.Add(new DataColumn { ColumnName = "C" + table.Columns.Count, Caption = "Column1" }); table.Columns.Add(new DataColumn { ColumnName = "C" + table.Columns.Count, Caption = "Column.2" }); table.Columns.Add(new DataColumn { ColumnName = "C" + table.Columns.Count, Caption = "Column3" }); table.Columns.Add(new DataColumn { ColumnName = "C" + table.Columns.Count, Caption = "Column4" }); for (int i = 0; i < 20; i++) { var row = table.NewRow(); for (int j = 0; j < table.Columns.Count; j++) { row[j] = "[" + (i + 1) + "," + (j + 1) + "]"; } table.Rows.Add(row); } this.DataContext = table;
private void DataGrid_OnAutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e) { var column = e.Column as DataGridBoundColumn; var view = (sender as DataGrid).ItemsSource as DataView; if (view != null && column != null) { var dataColumn = view.Table.Columns.OfType<DataColumn>().FirstOrDefault(c => c.ColumnName == e.PropertyName); if (dataColumn != null) { column.Header = dataColumn.Caption; } } }
ColumnNameは絶対にBindingPathの予約文字とかぶらないように、プログラム的に一意の文字列をふります。そして、Headerに表示したい文字列はCaptionを利用。その後、Column作成時にCaptionをHeaderに代入します。
ちなみに、DataTableはIndexで各ColumnとBindingができるので、そもそもAutoGenerateColumnでBindingを作成する際は、Indexでの解決にしてくれればよかったのに。。。と思ったりしないわけでもないのですが、どうなんでしょう。
# もしくは、BindingはColumnNameを使って、表示はCaptionを使うとか。
[…] 散々悩んで、泥庭というサイトを拝見しましたら、「これ、おんなじじゃね?」ということで、解決しました。泥庭の管理者さん、ありがとうございました。 […]
ピンバック by SQLのデータをピボットしたい | a scribbled memo — 2016年12月12日 @ 5:34 午後