0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

AIに頼り切ってタスクアプリを追加開発する。:機能追加

0
Last updated at Posted at 2026-05-21

前回までの概要

前回まででタスク管理アプリの大枠作成、ブラッシュアップをしました。
今回からは新機能の追加を実施します。

プロンプト

以下の機能(画面)を追加したいので、コードを出力してください。

・追加する機能
	・マスタ管理機能
		・新規作成
		・担当者、カテゴリ、工程をマスタ管理
	
	・wbs画面カラム修正機能
		・新規作成
		・現在wbs画面の項目は以下である
		  タスク,開始予定,終了予定,開始実績,終了実績,進捗,担当者,予定工数,実績工数,残工数,遅延,カテゴリ,工程,日付
		 上記以外にもタスクの保持する情報がある。
			→ユーザにより表示する項目とその順番を決めることができるよう、管理画面を追加したい。
		・機能
			・画面内容:一覧(datagrid等),項目移動ボタン(上下),削除ボタン,更新ボタン,キャンセルボタン
			      一覧内項目は以下
			      →No(label),固定(チェックボックス),項目(リスト)
			・初期表示:一覧へ現在のwbs表示項目が表示される。
			・修正:項目を選択、上下ボタン(ドラッグ&ドロップ)により順番を入れ替える。
			    削除ボタンより行を削除する。
			    「項目」のリストより機能を選択し、変更する。
			     →項目一覧はタスクの持つ全項目(複数持つ項目は除く)に加え、No項目(行数)を追加する。(一番上に追加)
			    
			    更新ボタン押下で更新、キャンセルボタンでキャンセルを行う。(共に警告メッセージ出力)

回答

# 追加方針

以下 2 機能を追加します。

機能 内容
マスタ管理 担当者、カテゴリ、工程
WBSカラム管理 表示項目、順序、固定列制御

追加構成

Forms
├─ MasterManageForm.cs
├─ MasterManageForm.Designer.cs
├─ WbsColumnSettingForm.cs
├─ WbsColumnSettingForm.Designer.cs

Domain
├─ MasterData.cs
├─ WbsColumnSetting.cs

Services
├─ MasterService.cs
├─ WbsColumnSettingService.cs

1. マスタ管理機能

新規追加 MasterData.cs

namespace TaskManager.Domain
{
    public class MasterData
    {
        public List<string> Assignees
        {
            get;
            set;
        } = new();

        public List<string> Categories
        {
            get;
            set;
        } = new();

        public List<string> Processes
        {
            get;
            set;
        } = new();
    }
}

新規追加 MasterService.cs

using System.Text.Json;
using TaskManager.Domain;

namespace TaskManager.Services
{
    public class MasterService
    {
        private const string FILE_PATH =
            "master.json";

        public MasterData Load()
        {
            if (!File.Exists(FILE_PATH))
            {
                return new MasterData();
            }

            string json =
                File.ReadAllText(FILE_PATH);

            return JsonSerializer.Deserialize<MasterData>(json)
                ?? new MasterData();
        }

        public void Save(MasterData data)
        {
            string json =
                JsonSerializer.Serialize(
                    data,
                    new JsonSerializerOptions
                    {
                        WriteIndented = true
                    });

            File.WriteAllText(
                FILE_PATH,
                json);
        }
    }
}

新規追加 MasterManageForm.Designer.cs

private TabControl tabMaster;

private TabPage tabAssignee;
private TabPage tabCategory;
private TabPage tabProcess;

private ListBox lstAssignee;
private ListBox lstCategory;
private ListBox lstProcess;

private Button btnAdd;
private Button btnDelete;
private Button btnSave;
private Button btnCancel;

InitializeComponent()

tabMaster = new TabControl();

tabAssignee = new TabPage("担当者");
tabCategory = new TabPage("カテゴリ");
tabProcess = new TabPage("工程");

lstAssignee = new ListBox();
lstCategory = new ListBox();
lstProcess = new ListBox();

btnAdd = new Button();
btnDelete = new Button();
btnSave = new Button();
btnCancel = new Button();

tabMaster.Dock = DockStyle.Top;

tabMaster.Height = 400;

lstAssignee.Dock = DockStyle.Fill;
lstCategory.Dock = DockStyle.Fill;
lstProcess.Dock = DockStyle.Fill;

tabAssignee.Controls.Add(lstAssignee);
tabCategory.Controls.Add(lstCategory);
tabProcess.Controls.Add(lstProcess);

tabMaster.TabPages.Add(tabAssignee);
tabMaster.TabPages.Add(tabCategory);
tabMaster.TabPages.Add(tabProcess);

btnAdd.Text = "追加";
btnDelete.Text = "削除";
btnSave.Text = "更新";
btnCancel.Text = "キャンセル";

btnAdd.Location = new Point(20, 420);
btnDelete.Location = new Point(120, 420);
btnSave.Location = new Point(220, 420);
btnCancel.Location = new Point(320, 420);

Controls.Add(tabMaster);

Controls.Add(btnAdd);
Controls.Add(btnDelete);
Controls.Add(btnSave);
Controls.Add(btnCancel);

ClientSize = new Size(500, 500);

新規追加 MasterManageForm.cs

using Microsoft.VisualBasic;
using TaskManager.Domain;
using TaskManager.Services;

namespace TaskManager.Forms
{
    public partial class MasterManageForm : Form
    {
        private readonly MasterService _service;

        private MasterData _data;

        public MasterManageForm()
        {
            InitializeComponent();

            _service = new MasterService();

            _data = _service.Load();

            LoadData();

            btnAdd.Click += btnAdd_Click;
            btnDelete.Click += btnDelete_Click;
            btnSave.Click += btnSave_Click;
            btnCancel.Click += btnCancel_Click;
        }

        private void LoadData()
        {
            lstAssignee.Items.Clear();
            lstCategory.Items.Clear();
            lstProcess.Items.Clear();

            lstAssignee.Items.AddRange(
                _data.Assignees.ToArray());

            lstCategory.Items.AddRange(
                _data.Categories.ToArray());

            lstProcess.Items.AddRange(
                _data.Processes.ToArray());
        }

        private ListBox CurrentList()
        {
            if (tabMaster.SelectedTab == tabAssignee)
            {
                return lstAssignee;
            }

            if (tabMaster.SelectedTab == tabCategory)
            {
                return lstCategory;
            }

            return lstProcess;
        }

        private void btnAdd_Click(
            object sender,
            EventArgs e)
        {
            string value =
                Interaction.InputBox(
                    "追加する値を入力してください");

            if (string.IsNullOrWhiteSpace(value))
            {
                return;
            }

            CurrentList().Items.Add(value);
        }

        private void btnDelete_Click(
            object sender,
            EventArgs e)
        {
            var list = CurrentList();

            if (list.SelectedIndex < 0)
            {
                return;
            }

            list.Items.RemoveAt(
                list.SelectedIndex);
        }

        private void btnSave_Click(
            object sender,
            EventArgs e)
        {
            if (MessageBox.Show(
                "更新しますか?",
                "確認",
                MessageBoxButtons.YesNo)
                != DialogResult.Yes)
            {
                return;
            }

            _data.Assignees =
                lstAssignee.Items
                    .Cast<string>()
                    .ToList();

            _data.Categories =
                lstCategory.Items
                    .Cast<string>()
                    .ToList();

            _data.Processes =
                lstProcess.Items
                    .Cast<string>()
                    .ToList();

            _service.Save(_data);

            MessageBox.Show("保存しました");
        }

        private void btnCancel_Click(
            object sender,
            EventArgs e)
        {
            if (MessageBox.Show(
                "変更を破棄しますか?",
                "確認",
                MessageBoxButtons.YesNo)
                != DialogResult.Yes)
            {
                return;
            }

            _data = _service.Load();

            LoadData();
        }
    }
}

2. WBSカラム設定機能

新規追加 WbsColumnSetting.cs

namespace TaskManager.Domain
{
    public class WbsColumnSetting
    {
        public int No
        {
            get;
            set;
        }

        public bool Fixed
        {
            get;
            set;
        }

        public string ColumnName
        {
            get;
            set;
        } = string.Empty;
    }
}

新規追加 WbsColumnSettingService.cs

using System.Text.Json;
using TaskManager.Domain;

namespace TaskManager.Services
{
    public class WbsColumnSettingService
    {
        private const string FILE_PATH =
            "wbs_columns.json";

        public List<WbsColumnSetting> Load()
        {
            if (!File.Exists(FILE_PATH))
            {
                return CreateDefault();
            }

            string json =
                File.ReadAllText(FILE_PATH);

            return JsonSerializer.Deserialize<
                List<WbsColumnSetting>>(json)
                ?? CreateDefault();
        }

        public void Save(
            List<WbsColumnSetting> settings)
        {
            string json =
                JsonSerializer.Serialize(
                    settings,
                    new JsonSerializerOptions
                    {
                        WriteIndented = true
                    });

            File.WriteAllText(
                FILE_PATH,
                json);
        }

        private List<WbsColumnSetting>
            CreateDefault()
        {
            string[] columns =
            {
                "タスク",
                "開始予定",
                "終了予定",
                "開始実績",
                "終了実績",
                "進捗",
                "担当者",
                "予定工数",
                "実績工数",
                "残工数",
                "遅延",
                "カテゴリ",
                "工程"
            };

            return columns
                .Select((x, i)
                    => new WbsColumnSetting
                    {
                        No = i + 1,
                        Fixed = true,
                        ColumnName = x
                    })
                .ToList();
        }
    }
}

新規追加 WbsColumnSettingForm.Designer.cs

private DataGridView dgvColumns;

private Button btnUp;
private Button btnDown;
private Button btnDelete;
private Button btnSave;
private Button btnCancel;

InitializeComponent()

dgvColumns =
    new DataGridView();

btnUp = new Button();
btnDown = new Button();
btnDelete = new Button();
btnSave = new Button();
btnCancel = new Button();

dgvColumns.Dock =
    DockStyle.Top;

dgvColumns.Height = 400;

dgvColumns.AllowUserToAddRows = false;

dgvColumns.Columns.Add(
    "No",
    "No");

var fixedCol =
    new DataGridViewCheckBoxColumn();

fixedCol.Name = "Fixed";

fixedCol.HeaderText = "固定";

dgvColumns.Columns.Add(fixedCol);

var combo =
    new DataGridViewComboBoxColumn();

combo.Name = "ColumnName";

combo.HeaderText = "項目";

combo.Items.AddRange(
    new object[]
    {
        "No",
        "タスク",
        "開始予定",
        "終了予定",
        "開始実績",
        "終了実績",
        "進捗",
        "担当者",
        "予定工数",
        "実績工数",
        "残工数",
        "遅延",
        "カテゴリ",
        "工程"
    });

dgvColumns.Columns.Add(combo);

btnUp.Text = "↑";
btnDown.Text = "↓";
btnDelete.Text = "削除";
btnSave.Text = "更新";
btnCancel.Text = "キャンセル";

btnUp.Location = new Point(20, 420);
btnDown.Location = new Point(100, 420);
btnDelete.Location = new Point(180, 420);
btnSave.Location = new Point(280, 420);
btnCancel.Location = new Point(380, 420);

Controls.Add(dgvColumns);

Controls.Add(btnUp);
Controls.Add(btnDown);
Controls.Add(btnDelete);
Controls.Add(btnSave);
Controls.Add(btnCancel);

ClientSize = new Size(700, 500);

新規追加 WbsColumnSettingForm.cs

using TaskManager.Domain;
using TaskManager.Services;

namespace TaskManager.Forms
{
    public partial class WbsColumnSettingForm : Form
    {
        private readonly
            WbsColumnSettingService _service;

        private List<WbsColumnSetting>
            _settings;

        public WbsColumnSettingForm()
        {
            InitializeComponent();

            _service =
                new WbsColumnSettingService();

            _settings =
                _service.Load();

            LoadData();

            btnUp.Click += btnUp_Click;
            btnDown.Click += btnDown_Click;
            btnDelete.Click += btnDelete_Click;
            btnSave.Click += btnSave_Click;
            btnCancel.Click += btnCancel_Click;
        }

        private void LoadData()
        {
            dgvColumns.Rows.Clear();

            foreach (var s in _settings)
            {
                dgvColumns.Rows.Add(
                    s.No,
                    s.Fixed,
                    s.ColumnName);
            }
        }

        private void btnUp_Click(
            object sender,
            EventArgs e)
        {
            MoveRow(-1);
        }

        private void btnDown_Click(
            object sender,
            EventArgs e)
        {
            MoveRow(1);
        }

        private void MoveRow(int offset)
        {
            if (dgvColumns.CurrentRow == null)
            {
                return;
            }

            int index =
                dgvColumns.CurrentRow.Index;

            int newIndex =
                index + offset;

            if (newIndex < 0 ||
                newIndex >= dgvColumns.Rows.Count)
            {
                return;
            }

            var row =
                dgvColumns.Rows[index];

            dgvColumns.Rows.RemoveAt(index);

            dgvColumns.Rows.Insert(
                newIndex,
                row);

            dgvColumns.CurrentCell =
                dgvColumns.Rows[newIndex]
                    .Cells[0];
        }

        private void btnDelete_Click(
            object sender,
            EventArgs e)
        {
            if (dgvColumns.CurrentRow == null)
            {
                return;
            }

            dgvColumns.Rows.Remove(
                dgvColumns.CurrentRow);
        }

        private void btnSave_Click(
            object sender,
            EventArgs e)
        {
            if (MessageBox.Show(
                "更新しますか?",
                "確認",
                MessageBoxButtons.YesNo)
                != DialogResult.Yes)
            {
                return;
            }

            _settings.Clear();

            for (int i = 0;
                 i < dgvColumns.Rows.Count;
                 i++)
            {
                var row =
                    dgvColumns.Rows[i];

                _settings.Add(
                    new WbsColumnSetting
                    {
                        No = i + 1,

                        Fixed =
                            Convert.ToBoolean(
                                row.Cells["Fixed"]
                                    .Value),

                        ColumnName =
                            row.Cells["ColumnName"]
                                .Value?
                                .ToString()
                                ?? ""
                    });
            }

            _service.Save(_settings);

            MessageBox.Show("保存しました");
        }

        private void btnCancel_Click(
            object sender,
            EventArgs e)
        {
            if (MessageBox.Show(
                "変更を破棄しますか?",
                "確認",
                MessageBoxButtons.YesNo)
                != DialogResult.Yes)
            {
                return;
            }

            _settings =
                _service.Load();

            LoadData();
        }
    }
}

WBS側反映

WbsForm.cs の InitializeGrid() を、

固定実装

↓

設定ファイル読込型

へ変更します。


追加

private readonly
    WbsColumnSettingService
        _columnService =
            new();

private List<WbsColumnSetting>
    _columnSettings;

コンストラクタ

_columnSettings =
    _columnService.Load();

InitializeGrid() 全変更

dgvWbs.Columns.Clear();

foreach (var setting
    in _columnSettings)
{
    dgvWbs.Columns.Add(
        setting.ColumnName,
        setting.ColumnName);

    dgvWbs.Columns[
        setting.ColumnName]
        .Frozen = setting.Fixed;
}

実装、起動確認

実際に実装、動かしてみるとこうなります。
image.png

マスタ管理

image.png

WBSカラム設定

image.png

まとめ

WBSの実用化も一旦完了かと思います。
次回は一覧画面への反映を行っていきます。

0
0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?