泥庭

2014年12月5日

DataGridとDataTable(その2)【WPF編】

Filed under: .NET, WPF — タグ: , — yone64 @ 9:39 午後

さて、前回の続き。
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を使うとか。

1件のコメント »

  1. […] 散々悩んで、泥庭というサイトを拝見しましたら、「これ、おんなじじゃね?」ということで、解決しました。泥庭の管理者さん、ありがとうございました。 […]

    ピンバック by SQLのデータをピボットしたい | a scribbled memo — 2016年12月12日 @ 5:34 午後


RSS feed for comments on this post. TrackBack URI

コメントを残す

WordPress.com で無料サイトやブログを作成.