LoginSignup
6
14

More than 5 years have passed since last update.

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

Posted at

作るもの

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の行ヘッダに行番号を表示

6
14
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
14