前回までの概要
前回まででタスク管理アプリの大枠作成、ブラッシュアップ中となっています。
今回はWBS、ガントチャート画面を再度ブラッシュアップします。
プロンプト
WBS画面のガントチャートに以下要件を追加したい。
・月ヘッダ
・今日線
回答
WbsForm.Designer.cs 修正版
追加コントロール
private Panel pnlMonthHeader;
InitializeComponent 修正
private void InitializeComponent()
{
pnlMonthHeader = new Panel();
dgvWbs = new DataGridView();
((System.ComponentModel.ISupportInitialize)
dgvWbs).BeginInit();
SuspendLayout();
// pnlMonthHeader
pnlMonthHeader.Dock = DockStyle.Top;
pnlMonthHeader.Height = 35;
pnlMonthHeader.BackColor = Color.White;
pnlMonthHeader.Paint += pnlMonthHeader_Paint;
// dgvWbs
dgvWbs.Dock = DockStyle.Fill;
dgvWbs.Location = new Point(0, 35);
dgvWbs.Name = "dgvWbs";
dgvWbs.RowTemplate.Height = 28;
dgvWbs.Scroll += dgvWbs_Scroll;
dgvWbs.CellPainting += dgvWbs_CellPainting;
// WbsForm
AutoScaleDimensions =
new SizeF(7F, 15F);
AutoScaleMode =
AutoScaleMode.Font;
ClientSize =
new Size(1400, 700);
Controls.Add(dgvWbs);
Controls.Add(pnlMonthHeader);
Name = "WbsForm";
Text = "WBS";
WindowState =
FormWindowState.Maximized;
((System.ComponentModel.ISupportInitialize)
dgvWbs).EndInit();
ResumeLayout(false);
}
WbsForm.cs 修正版
フィールド追加
private DateTime _minDate;
private DateTime _maxDate;
private const int DATE_COLUMN_WIDTH = 50;
LoadWbs 修正
private void LoadWbs()
{
var rows =
_wbsService.BuildRows(
_taskService.GetAll());
if (rows.Count == 0)
{
return;
}
_minDate =
rows.Min(x => x.StartDate);
_maxDate =
rows.Max(x => x.EndDate);
int days =
(_maxDate - _minDate).Days + 1;
// 日付列追加
for (int i = 0; i < days; i++)
{
DateTime day =
_minDate.AddDays(i);
var column =
new DataGridViewTextBoxColumn();
column.Name =
day.ToString("yyyyMMdd");
column.HeaderText =
day.ToString("dd");
column.Width =
DATE_COLUMN_WIDTH;
column.SortMode =
DataGridViewColumnSortMode.NotSortable;
// 土日色分け
if (day.DayOfWeek ==
DayOfWeek.Saturday ||
day.DayOfWeek ==
DayOfWeek.Sunday)
{
column.DefaultCellStyle.BackColor =
Color.AliceBlue;
}
dgvWbs.Columns.Add(column);
}
foreach (var row in rows)
{
int index =
dgvWbs.Rows.Add();
var gridRow =
dgvWbs.Rows[index];
gridRow.Cells[0].Value =
new string(' ', row.Level * 4)
+ row.TaskName;
gridRow.Cells[1].Value =
row.StartDate.ToString("yyyy/MM/dd");
gridRow.Cells[2].Value =
row.EndDate.ToString("yyyy/MM/dd");
for (DateTime d = row.StartDate;
d <= row.EndDate;
d = d.AddDays(1))
{
int col =
3 + (d - _minDate).Days;
gridRow.Cells[col].Style.BackColor =
Color.DodgerBlue;
}
}
pnlMonthHeader.Invalidate();
}
月ヘッダ描画
重要部分です。
private void pnlMonthHeader_Paint(
object sender,
PaintEventArgs e)
{
Graphics g = e.Graphics;
g.Clear(Color.White);
int fixedWidth =
dgvWbs.Columns[0].Width +
dgvWbs.Columns[1].Width +
dgvWbs.Columns[2].Width;
DateTime current =
new DateTime(
_minDate.Year,
_minDate.Month,
1);
while (current <= _maxDate)
{
DateTime monthEnd =
current.AddMonths(1).AddDays(-1);
if (monthEnd > _maxDate)
{
monthEnd = _maxDate;
}
int startOffset =
(current - _minDate).Days;
if (startOffset < 0)
{
startOffset = 0;
}
int endOffset =
(monthEnd - _minDate).Days;
int x =
fixedWidth +
startOffset * DATE_COLUMN_WIDTH;
int width =
(endOffset - startOffset + 1)
* DATE_COLUMN_WIDTH;
Rectangle rect =
new Rectangle(
x,
0,
width,
pnlMonthHeader.Height);
g.FillRectangle(
Brushes.LightGray,
rect);
g.DrawRectangle(
Pens.Gray,
rect);
StringFormat sf =
new StringFormat();
sf.Alignment =
StringAlignment.Center;
sf.LineAlignment =
StringAlignment.Center;
g.DrawString(
current.ToString("yyyy/MM"),
Font,
Brushes.Black,
rect,
sf);
current =
current.AddMonths(1);
}
}
今日線描画
かなり重要。
dgvWbs_CellPainting
private void dgvWbs_CellPainting(
object sender,
DataGridViewCellPaintingEventArgs e)
{
if (e.RowIndex < 0 ||
e.ColumnIndex < 3)
{
return;
}
DateTime columnDate =
_minDate.AddDays(
e.ColumnIndex - 3);
if (columnDate.Date ==
DateTime.Today)
{
e.Paint(e.CellBounds,
DataGridViewPaintParts.All);
using Pen pen =
new Pen(Color.Red, 2);
e.Graphics.DrawLine(
pen,
e.CellBounds.Left,
e.CellBounds.Top,
e.CellBounds.Left,
e.CellBounds.Bottom);
e.Handled = true;
}
}
スクロール同期
これがないと月ヘッダがズレます。
private void dgvWbs_Scroll(
object sender,
ScrollEventArgs e)
{
pnlMonthHeader.Invalidate();
}
実装、起動確認
実際に実装、動かしてみるとこうなります。
まとめ
WBSの実用化も一旦完了かと思います。
次回はタスクに持つ項目のブラッシュアップを予定しています。
