C#で作るプロジェクト管理アプリケーション(その2)

## 1.最初に言わせてくださいぃぃ！
その1執筆してたらページがすんごく重くなったので、中途半端なところで切り上げました(泣)
効率下がってモチベが低くなってしまうので、開き直ってその2を書くことにしました。
中途半端なその1のカードおいておきます…。

https://qiita.com/sumiyoshi01/items/95ebe80e10882d845209

## 2.各コード(その2)

```diff_c_sharp:IdeaItem.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace task_manager_for_research
{
    public class IdeaItem
    {
        public string TaskName { get; set; }  
        public string Idea { get; set; }   
        public string Date { get; set; }      
    }


}


```

```diff_c_sharp:Project.cs
using System.Collections.Generic;
using task_manager_for_research;

public class Project
{
    public string ProjectName { get; set; }
    public string TaskFilePath { get; set; }
    public string CompletedTaskFilePath { get; set; }

    public string ScheduleFilePath { get; set; }

    public string ReferenceFilePath { get; set; } 
    public List<TaskItem> Tasks { get; set; } = new List<TaskItem>();
    public List<TaskItem> CompletedTasks { get; set; } = new List<TaskItem>();
    public List<ScheduleItem> Schedules { get; set; } = new List<ScheduleItem>();

    public List<ReferenceItem> References { get; set; } = new List<ReferenceItem>(); 

    public string IdeaFilePath { get; set; }
    public List<IdeaItem> Ideas { get; set; } = new List<IdeaItem>();
}


```

```diff_c_sharp:ProjectManager.cs
using System;
using System.Collections.Generic;
using System.IO;

namespace task_manager_for_research
{
    public static class ProjectManager
    {
        private const string ProjectsFilePath = "projects.txt";

        public static List<Project> LoadProjects()
        {
            var projects = new List<Project>();
            if (File.Exists(ProjectsFilePath))
            {
                using (var reader = new StreamReader(ProjectsFilePath))
                {
                    string line;
                    while ((line = reader.ReadLine()) != null)
                    {
                        var data = line.Split(';');
                        var projectName = data[0];
                        var taskFilePath = data.Length > 1 ? data[1] : Path.Combine(AppDomain.CurrentDomain.BaseDirectory, $"{projectName}_tasks.csv");
                        var completedTaskFilePath = data.Length > 2 ? data[2] : Path.Combine(AppDomain.CurrentDomain.BaseDirectory, $"{projectName}_completed_tasks.csv");
                        var scheduleFilePath = data.Length > 3 ? data[3] : Path.Combine(AppDomain.CurrentDomain.BaseDirectory, $"{projectName}_schedules.csv");
                        var referenceFilePath = data.Length > 4 ? data[4] : Path.Combine(AppDomain.CurrentDomain.BaseDirectory, $"{projectName}_references.csv");
                        var ideaFilePath = data.Length > 5 ? data[5] : Path.Combine(AppDomain.CurrentDomain.BaseDirectory, $"{projectName}_ideas.csv");

                        var project = new Project
                        {
                            ProjectName = projectName,
                            TaskFilePath = taskFilePath,
                            CompletedTaskFilePath = completedTaskFilePath,
                            ScheduleFilePath = scheduleFilePath,
                            ReferenceFilePath = referenceFilePath,
                            IdeaFilePath = ideaFilePath
                        };
                        projects.Add(project);
                    }
                }
            }
            return projects;
        }

        public static void SaveProjects(List<Project> projects)
        {
            using (var writer = new StreamWriter(ProjectsFilePath))
            {
                foreach (var project in projects)
                {
                    writer.WriteLine($"{project.ProjectName};{project.TaskFilePath};{project.CompletedTaskFilePath};{project.ScheduleFilePath};{project.ReferenceFilePath};{project.IdeaFilePath}");
                }
            }
        }
    }
}

```

```diff_c_sharp:ReferenceItem.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace task_manager_for_research
{
    public class ReferenceItem
    {
        public string ReferenceType { get; set; } 
        public string Reference { get; set; }
        public string Date { get; set; }
        public string Content { get; set; }
        public string Author { get; set; } 

        public string Display => ReferenceType == "Link" ? Reference : $"{Reference} by {Author}";
    }

}

```

```diff_c_sharp:ScheduleItem.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace task_manager_for_research
{
    public class ScheduleItem
    { 
            public string ScheduleName { get; set; }
            public string ScheduleDate { get; set; }
        
    }
}

```

```diff_c_sharp:TaskItem.cs
using System.ComponentModel;

namespace task_manager_for_research
{
    public class TaskItem : INotifyPropertyChanged
    {
        private string taskName;
        private string startDate;
        private string endDate;
        private string completionDate;
        private string review;

        public string TaskName
        {
            get => taskName;
            set
            {
                taskName = value;
                OnPropertyChanged(nameof(TaskName));
            }
        }

        public string StartDate
        {
            get => startDate;
            set
            {
                startDate = value;
                OnPropertyChanged(nameof(StartDate));
            }
        }

        public string EndDate
        {
            get => endDate;
            set
            {
                endDate = value;
                OnPropertyChanged(nameof(EndDate));
            }
        }

        public string CompletionDate
        {
            get => completionDate;
            set
            {
                completionDate = value;
                OnPropertyChanged(nameof(CompletionDate));
            }
        }

        public string Review
        {
            get => review;
            set
            {
                review = value;
                OnPropertyChanged(nameof(Review));
            }
        }

       

        public override string ToString()
            {
                return TaskName;
            }
        


        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void OnPropertyChanged(string propertyName)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

```

各クラスのファイルは以上です。一応、編集などのダイアログのビューファイルとビハインドコードもありますが、割愛します。(要望があれば載せます！)

## 3.ライブラリの説明

### `System`
- 基本的なC#プログラムに必要な基本クラスやデータ型を提供する。

### `System.Collections.Generic`
- ジェネリックコレクションを提供し、型安全なリストやディクショナリなどのコレクションを使用可能にする。

### `System.IO`
- ファイルやデータストリームの読み書きに関する機能を提供する。

### `System.Linq`
- LINQ (Language Integrated Query)を使用してデータのクエリや操作を簡単に行うための機能を提供する。

### `System.Windows`
- WPFアプリケーションの基本クラスや機能を提供する。
※WPFは「Windows Presentation Foundation」の略。
  Microsoftが開発したユーザーインターフェイス（UI）フレームワークで、Windowsデスクトップアプリケーションの開発に使用される。

### `System.Windows.Controls`
- WPFのコントロール(ボタン、テキストボックスなど)を提供する。

### `System.Windows.Data`
- データバインディングのためのクラスを提供する。

### `System.Windows.Media`
- グラフィックスやアニメーションの処理を行うクラスを提供する。

### `System.Diagnostics`
- デバッグやトレースのためのクラスを提供する。

### `OpenQA.Selenium`
- Selenium WebDriverの基本機能を提供する。ブラウザの自動操作を行う。

### `OpenQA.Selenium.Chrome`
- Chromeブラウザの操作に特化したSelenium WebDriverを提供する。

### `HtmlAgilityPack`
- HTMLドキュメントを操作するためのライブラリで、HTMLの解析や操作を行う。

### `System.Threading.Tasks`
- 非同期プログラミングを行うためのクラスを提供する。

## 4.メソッドの役割とオブジェクト指向の構成

### `MainWindow`クラス
- WPFアプリケーションのメインウィンドウを定義するクラスであり、プロジェクト管理アプリケーションの主要な機能を提供する。

### コンストラクタ `MainWindow()`
- ウィンドウを初期化し、プロジェクトのタブを設定する。

### `FetchTasksButton_Click`
- Manabaからタスクを取得し、表示するための非同期メソッドである。

### `GetTasksFromyourschool`
- Seleniumを使用して掲示板からタスクを取得し、HTML Agility Packを使用してタスクデータを解析する。

### `DisplayTasks`
- 取得したタスクを新しいウィンドウに表示する。

### `InitializeProjectTabs`
- プロジェクトごとにタブを初期化し、選択されたタブの内容を表示する。

### `CreateProjectTabContent`
- プロジェクトのタブのコンテンツを生成する。各タブにはタスク管理、スケジュール管理、参考文献管理、フィードバック、アイデアの機能が含まれる。

### `CreateTaskContent`
- タスク管理タブのコンテンツを生成し、タスクを表示、追加、編集、完了するためのUI要素を設定する。

### `CreateScheduleContent`
- スケジュール管理タブのコンテンツを生成し、スケジュールの追加と表示を行う。

### `CreateReferenceContent`
- 参考文献管理タブのコンテンツを生成し、参考文献の追加と表示を行う。

### `CreateFeedbackContent`
- フィードバックタブのコンテンツを生成し、完了したタスクのレビューを表示する。

### `CreateIdeaContent`
- アイデアタブのコンテンツを生成し、タスクに関連するアイデアを追加、表示する。

### `SetPlaceholderText`
- テキストボックスにプレースホルダーテキストを設定する。

### `LoadTasks`
- プロジェクトのタスクリストを読み込み、表示する。

### `AddTaskButton_Click`
- 新しいタスクを追加するためのメソッドである。

### `CompleteTask`
- タスクを完了としてマークし、プロジェクトの完了タスクリストに移動する。

### `EditTask`
- タスクの編集を行うためのメソッドである。

### `WriteReview`
- タスクのレビューを書き込むためのメソッドである。

### `SaveTasks`, `SaveSchedules`, `SaveReferences`, `SaveIdeas`
- タスク、スケジュール、参考文献、アイデアをファイルに保存する。

### `LoadSchedules`, `LoadReferences`, `LoadIdeas`
- スケジュール、参考文献、アイデアをファイルから読み込む。

### `AddProjectButton_Click`, `EditProjectButton_Click`, `DeleteProjectButton_Click`
- プロジェクトの追加、編集、削除を行うためのメソッドである。

### `PromptForProjectName`
- プロジェクト名を入力するためのダイアログを表示し、ユーザーから入力を受け取る。

### `CreateFileIfNotExists`
- ファイルが存在しない場合に新規作成する。

### `MainWindow_Closing`
- ウィンドウを閉じる際に、プロジェクトデータを保存する。

### `ProjectTabControl_SelectionChanged`
- プロジェクトタブの選択変更時に、選択されたプロジェクトのタスクリストを表示する。

### `RefreshTaskListView`
- タスクリストビューを更新する。

### `GetIdeaTaskListView`
- アイデアタブのタスクリストビューを取得する。

### `RefreshIdeaTaskListView`
- アイデアタブのタスクリストビューを更新する。

## 5.オブジェクト指向について
C#はオブジェクト指向の言語といわれています。実際、クラスごとにファイルを分け、それぞれ管理しました。
オブジェクト指向には3つの特徴があります。
1. カプセル化
1. 継承
1. ポリモーフィズム

カプセル化は外部からのアクセスができないように、クラス内でデータとメソッドをまとめて保護することです。こうすることによって、データの整合性を担保することができます。
今回のコードで例えると、

```diff_c_sharp
public string StartDate
        {
            get => startDate;
            set
            {
                startDate = value;
                OnPropertyChanged(nameof(StartDate));
            }
        }

```
はカプセル化していると言えます。つまり、「開始日が値である」ということが担保されている状態です。
`getter`と`setter`にもそれぞれちゃんと意味があります。
getterはプライベートフィールドの値を外部に公開することができます。また、フィールドの値を取得する際にログの記録といった追加の処理を行うことができます。
setterはプライベートフィールドの値を変更することができます。また、検証や追加の処理を行うことができます。
これらの働きによってデータを守っています。

次に、継承ですが、これは親クラスの機能を受け継ぐことでコードの重複を防ぐという特徴になります。今回のコードでは利用していないので割愛します。

最後にポリモーフィズムです。これは異なるクラス間でメソッドを共有することでコードを少なくするという特徴です。今回のコードでは
```diff_c_sharp
public string CompletionDate
        {
            get => completionDate;
            set
            {
                completionDate = value;
                OnPropertyChanged(nameof(CompletionDate));
            }
        }

        public string Review
        {
            get => review;
            set
            {
                review = value;
                OnPropertyChanged(nameof(Review));
            }
        }

       

        public override string ToString()
            {
                return TaskName;
            }
        


        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void OnPropertyChanged(string propertyName)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }
```
このあたりで使われています。
`OnPropertyChanged`というメソッドを共有していることがわかります。同じメソッドを使っていますが、挙動は異なります。

以上のように、コードを少しでも減らし、管理しやすくできるところがオブジェクト指向のいいところです。

## 6.まとめ
今回はC#を用いてアプリケーションを作成しました。webページにアクセスできるという点では意外と融通が利く言語なんだと思いました(大分失礼)。
本当はスクレイピングの非同期処理のところとかいろいろ説明したいのですが、また今度、元気があったらしたいと思います。最後まで見てくださりありがとうございました。続編があったら、またお会いしましょう～