C#
WPF
VisualStudio

WPF DataGridでDataTableを行ヘッダー付きで表示する

More than 1 year has passed since last update.


作るもの

DataGridの列ヘッダーをカレンダーみたいに日付表示させて

行ヘッダーに人名、セルに○とかを表示させるものを考えた

2017-05-19_20h33_55.png


Model

まずModel

public class Model

{
public DataTable _DataTable { get; set; } = new DataTable();
public int _Year { get; set; } = 2017;
public int _Month { get; set; } = 1;

public Model()
{
string[] lName = {"伊藤","山本","佐藤","鈴木","佐々木","田中","宮本","神谷","池田","岡本" };
string[] fName = {"大輔","太郎","正和","一郎","聡","豊","徹","涼介","人志","将人" };
string[] State = { "-", "△", "◯", "✕" };

Random random = new Random();

_DataTable.Columns.Add("RowHeader");
for (int i = 1; i < DateTime.DaysInMonth(_Year,_Month); i++)
{
_DataTable.Columns.Add(i.ToString());
}

for (int i = 0; i < 20; i++)
{
var row = _DataTable.NewRow();
for (int j = 0; j < _DataTable.Columns.Count; j++)
{
if (j == 0)
{
row[j] = lName[random.Next(lName.Length)] + fName[random.Next(fName.Length)];
}
else
{
row[j] = State[random.Next(State.Length)];
}
}
_DataTable.Rows.Add(row);
}
}
}

DataTableの最初の列には人名を入れるため

_DataTable.Columns.Add("RowHeader");としている

あとは指定年月の日数分DataTableに列を追加している

んでRowとCellには配列からランダムに値を入れている

サンプルとかでもこういう遊びがほしくなる('ω')


ViewModel

いつものViewModelだよ

    public class ViewModel

{
public Model _Model { get; } = new Model();
}


View

ここがなかなかややこしいポイント

        <DataGrid x:Name="myDataGrid" ItemsSource="{Binding _Model._DataTable}" CanUserReorderColumns="False" CanUserSortColumns="False" CanUserAddRows="False" CanUserDeleteRows="False" AutoGeneratingColumn="myDataGrid_AutoGeneratingColumn">

<DataGrid.CellStyle>
<Style TargetType="{x:Type DataGridCell}">
<Setter Property="TextBlock.TextAlignment" Value="Center"/>
</Style>
</DataGrid.CellStyle>
<DataGrid.ColumnHeaderStyle>
<Style TargetType="{x:Type DataGridColumnHeader}">
<Setter Property="HorizontalContentAlignment" Value="Center"/>
</Style>
</DataGrid.ColumnHeaderStyle>
<DataGrid.RowHeaderStyle>
<Style TargetType="{x:Type DataGridRowHeader}">
<Setter Property="Content" Value="{Binding [0]}"/>
</Style>
</DataGrid.RowHeaderStyle>
</DataGrid>

まずDataGrid.CellStyle

ここではStyleでCellないのTextが中央に表示されるようにしている

列の幅を変えても中央に表示されるよ(゚∀゚)

んでDataGrid.ColumnHeaderStyle

ここでも設定しているのはセルと同じこと

ヘッダー内の文字が中央にくるようにしている

最後にDataGrid.RowHeaderStyle

これがキモ

Styleを使ってDataGridRowHeaderに渡されるデータの最初の列をバインドしている

しかし、AutoGenerateColumnsがTrueなのでこれを実行するとこうなる

2017-05-19_21h11_17.png

まあ当然だよね

そこで、AutoGeneratingColumnイベントで1列目の列生成だけキャンセルすることにする

        private void myDataGrid_AutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e)

{
if (e.PropertyName == "RowHeader")
{
e.Cancel = true;
}
}

これもcounterみたいなのを作ってindexで判定すると汎用性が上がると思う


まとめ

最初はDataGridに行列の数が不確定なコレクションを表示させたくていろいろ調べた結果こうなった

これだとDataTable側をいじればDataGrid側をいじる必要がなくなるから便利

あとはReactivePropertyとか使ってデータの操作とかもしてみたい


参考

WPF Notes/DataGridの行ヘッダに行番号を表示