CSVとDataGridViewで疑似DB

# 環境
VisualStudio2019
C++/cli
CLRプロジェクト(.NetFlameWork)
.NetFlameWork4.7.2

# やりたいこと
あまり使う機会はないと思うが、業務上WindowsFormアプリケーション作成をすることが多い
その中でcsvファイルを保存先として、DataGridViewの内容を保存したり、逆にcsvの内容を読み取って表示したりということがあるので、メモとして残しておく

![data1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3746814/52290a71-8f84-e5f8-2b3e-b122020af530.png)
上記のようなcsvファイルを読み取ったり編集する

A列目がキーとなる値でP列目までの値が必須項目、それ以降の値は行によって入っていたりいなかったりする追加要素
この追加要素をフォーム上で追加したり、編集したりする

![form1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3746814/17e2360d-9cfe-ad83-8542-6d9b8974399d.png)

まず、最初のフォームを立ち上げたときにDGV上に現在のキー値が列挙される
このキー値はダブルクリックしたときに編集可能となるので、ContextMenuStripを使って右クリック時に別のフォームを開くようにする

# コード

```MyForm.cpp
#include "MyForm.h"
#include "MyForm1.h"

using namespace testProjectdgv;
using namespace System::IO;
using namespace System::Text;
using namespace System::Collections::Generic;

[STAThreadAttribute]

int main() {
	Application::Run(gcnew MyForm());
	return 0;
}

System::Void testProjectdgv::MyForm::contextMenuStrip1_Opening(System::Object^ sender, System::ComponentModel::CancelEventArgs^ e)
{
    String^ key;
    for each (DataGridViewCell ^ c in dataGridView1->SelectedCells)
    {
        key=dataGridView1->Rows[c->RowIndex]->Cells[0]->Value->ToString();

    }
    MyForm1^ m1 = gcnew MyForm1(key);
    m1->Show();
    return System::Void();
}

System::Void testProjectdgv::MyForm::MyForm_Load(System::Object^ sender, System::EventArgs^ e)
{
	String^ path = "csvファイル名";
    StreamReader^ sr = gcnew StreamReader(path, Encoding::UTF8);
    List<String^>^ titleList = gcnew List<String^>;
    String^ n = "";
    try {
        //headerを飛ばす
        sr->ReadLine();
        while (sr->Peek() > 0) {
            String^ line = sr->ReadLine();
            cli::array<String^>^ arr = line->Split(',');
            if (arr[0] == "END") break;
            //titleを取得
            titleList->Add(arr[0]);
        }
    }
    catch (Exception^ e) {
        MessageBox::Show(e->ToString());
    }
    finally {
        sr->Close();
    }
    for (int i = 0; i < titleList->Count; i++) {
        dataGridView1->Rows->Add();
        dataGridView1->Rows[dataGridView1->RowCount - 1]->Cells[0]->Value = titleList[i];
    }
    dataGridView1->Refresh();
	return System::Void();
}
```
ヘッダーファイル(.h)とソースファイル(.cpp)がありますが、hは触っていないのでcppだけ書いておく

![form2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3746814/8425570a-997b-694c-c46e-e6ca0c907284.png)

右クリック時のキー値を取得して、csvから追加データを読み取り、初期値として表示する
ボタンは追加、削除、登録の三つ
追加は行追加で、削除は選択行削除で、登録は現在のDataGridViewの状態をcsvに書き込む

# コード

```MyForm1.h
#pragma once

namespace testProjectdgv {

	using namespace System;
	using namespace System::ComponentModel;
	using namespace System::Collections;
	using namespace System::Windows::Forms;
	using namespace System::Data;
	using namespace System::Drawing;

	/// <summary>
	/// MyForm1 の概要
	/// </summary>
	public ref class MyForm1 : public System::Windows::Forms::Form
	{
	public:
		MyForm1(void)
		{
			InitializeComponent();
			//
			//TODO: ここにコンストラクター コードを追加します
			//
		}
		MyForm1(String^ key) {
			InitializeComponent();
			//
			//TODO: ここにコンストラクター コードを追加します
			//
			keyVal = key;
		}

	protected:
		/// <summary>
		/// 使用中のリソースをすべてクリーンアップします。
		/// </summary>
		~MyForm1()
		{
			if (components)
			{
				delete components;
			}
		}
	private: System::Windows::Forms::DataGridView^ dataGridView1;
	private: System::Windows::Forms::Button^ button1;
	private: System::Windows::Forms::Button^ button2;
	private: System::Windows::Forms::Button^ button3;
	private: System::Windows::Forms::DataGridViewTextBoxColumn^ Column1;
	protected:

	private:
		/// <summary>
		/// 必要なデザイナー変数です。
		/// </summary>
		System::ComponentModel::Container ^components;

#pragma region Windows Form Designer generated code
		/// <summary>
		/// デザイナー サポートに必要なメソッドです。このメソッドの内容を
		/// コード エディターで変更しないでください。
		/// </summary>
		void InitializeComponent(void)
		{
			this->dataGridView1 = (gcnew System::Windows::Forms::DataGridView());
			this->button1 = (gcnew System::Windows::Forms::Button());
			this->button2 = (gcnew System::Windows::Forms::Button());
			this->button3 = (gcnew System::Windows::Forms::Button());
			this->Column1 = (gcnew System::Windows::Forms::DataGridViewTextBoxColumn());
			(cli::safe_cast<System::ComponentModel::ISupportInitialize^>(this->dataGridView1))->BeginInit();
			this->SuspendLayout();
			// 
			// dataGridView1
			// 
			this->dataGridView1->AllowUserToAddRows = false;
			this->dataGridView1->AllowUserToDeleteRows = false;
			this->dataGridView1->AllowUserToResizeColumns = false;
			this->dataGridView1->AllowUserToResizeRows = false;
			this->dataGridView1->ColumnHeadersHeightSizeMode = System::Windows::Forms::DataGridViewColumnHeadersHeightSizeMode::AutoSize;
			this->dataGridView1->Columns->AddRange(gcnew cli::array< System::Windows::Forms::DataGridViewColumn^  >(1) { this->Column1 });
			this->dataGridView1->Location = System::Drawing::Point(12, 12);
			this->dataGridView1->Name = L"dataGridView1";
			this->dataGridView1->RowTemplate->Height = 21;
			this->dataGridView1->Size = System::Drawing::Size(240, 150);
			this->dataGridView1->TabIndex = 0;
			// 
			// button1
			// 
			this->button1->Location = System::Drawing::Point(12, 185);
			this->button1->Name = L"button1";
			this->button1->Size = System::Drawing::Size(75, 23);
			this->button1->TabIndex = 1;
			this->button1->Text = L"追加";
			this->button1->UseVisualStyleBackColor = true;
			this->button1->Click += gcnew System::EventHandler(this, &MyForm1::button1_Click);
			// 
			// button2
			// 
			this->button2->Location = System::Drawing::Point(105, 185);
			this->button2->Name = L"button2";
			this->button2->Size = System::Drawing::Size(75, 23);
			this->button2->TabIndex = 2;
			this->button2->Text = L"削除";
			this->button2->UseVisualStyleBackColor = true;
			this->button2->Click += gcnew System::EventHandler(this, &MyForm1::button2_Click);
			// 
			// button3
			// 
			this->button3->Location = System::Drawing::Point(199, 185);
			this->button3->Name = L"button3";
			this->button3->Size = System::Drawing::Size(75, 23);
			this->button3->TabIndex = 3;
			this->button3->Text = L"登録";
			this->button3->UseVisualStyleBackColor = true;
			this->button3->Click += gcnew System::EventHandler(this, &MyForm1::button3_Click);
			// 
			// Column1
			// 
			this->Column1->HeaderText = L"内訳";
			this->Column1->Name = L"Column1";
			// 
			// MyForm1
			// 
			this->AutoScaleDimensions = System::Drawing::SizeF(6, 12);
			this->AutoScaleMode = System::Windows::Forms::AutoScaleMode::Font;
			this->ClientSize = System::Drawing::Size(284, 261);
			this->Controls->Add(this->button3);
			this->Controls->Add(this->button2);
			this->Controls->Add(this->button1);
			this->Controls->Add(this->dataGridView1);
			this->Name = L"MyForm1";
			this->Text = L"MyForm1";
			this->Load += gcnew System::EventHandler(this, &MyForm1::MyForm1_Load);
			(cli::safe_cast<System::ComponentModel::ISupportInitialize^>(this->dataGridView1))->EndInit();
			this->ResumeLayout(false);

		}
#pragma endregion
	private: String^ keyVal;
	private: int addNum=16;
	private: System::Void MyForm1_Load(System::Object^ sender, System::EventArgs^ e);
	private: System::Void button1_Click(System::Object^ sender, System::EventArgs^ e);
	private: System::Void button2_Click(System::Object^ sender, System::EventArgs^ e);
	private: System::Void button3_Click(System::Object^ sender, System::EventArgs^ e);
};
}
```

```MyForm1.cpp
#include "MyForm1.h"

using namespace testProjectdgv;
using namespace System::IO;
using namespace System::Text;
using namespace System::Collections::Generic;

System::Void testProjectdgv::MyForm1::MyForm1_Load(System::Object^ sender, System::EventArgs^ e)
{
    String^ path = "csvファイル名";
    StreamReader^ sr = gcnew StreamReader(path, Encoding::UTF8);
    List<String^>^ keyList = gcnew List<String^>;
    String^ n = "";
    try {
        //headerを飛ばす
        sr->ReadLine();
        while (sr->Peek() > 0) {
            String^ line = sr->ReadLine();
            cli::array<String^>^ arr = line->Split(',');
            if (arr[0] == "END") break;
            //keyとなる値から検索
            if (arr[0] == keyVal) {
                //データの最大長を取得
                int num = arr->Length;
                //追加データがあるか判定
                if (arr[addNum] != "" && arr[addNum] != nullptr) {
                    //ある場合はカンマ区切りで取得
                    for (int i = addNum; i < num; i++) {
                        if (arr[i] == "" || i == num - 1) {
                            keyList->Add(arr[i]);
                            break;
                        }
                        else {
                            keyList->Add(arr[i]);
                        }
                    }
                }
            }
        }
    }
    catch (Exception^ e) {
        MessageBox::Show(e->ToString());
    }
    finally {
        sr->Close();
    }
    for (int i = 0; i < keyList->Count; i++) {
        dataGridView1->Rows->Add();
        dataGridView1->Rows[dataGridView1->RowCount - 1]->Cells[0]->Value = keyList[i];
    }
    
    return System::Void();
}

System::Void testProjectdgv::MyForm1::button1_Click(System::Object^ sender, System::EventArgs^ e)
{
    dataGridView1->Rows->Add();
    return System::Void();
}

System::Void testProjectdgv::MyForm1::button2_Click(System::Object^ sender, System::EventArgs^ e)
{
    for each (DataGridViewRow ^ r in dataGridView1->SelectedRows)
    {
        dataGridView1->Rows->RemoveAt(r->Index);
    }

    for each (DataGridViewCell ^ c in dataGridView1->SelectedCells)
    {
        dataGridView1->Rows->RemoveAt(c->RowIndex);
    }
    return System::Void();
}

System::Void testProjectdgv::MyForm1::button3_Click(System::Object^ sender, System::EventArgs^ e)
{
    String^ path = "csvファイル名";
    StreamReader^ sr = gcnew StreamReader(path, Encoding::UTF8);
    List<String^>^ bdArr = gcnew List<String^>;
    try {
        //headerを飛ばす
        bdArr->Add(sr->ReadLine());
        while (sr->Peek() > 0) {
            String^ line = sr->ReadLine();
            cli::array<String^>^ arr = line->Split(',');
            if (arr[0] == "END") {
                bdArr->Add(line);
                break;
            }
            //keyとなる値から検索
            if (arr[0] == keyVal) {
                cli::array<String^>^ arr = line->Split(',');
                String^ afLine = "";
                String^ sep = ",";
                for (int j = 0; j < addNum; j++) {
                    afLine += arr[j]+sep;
                }
                for (int n = 0; n < dataGridView1->RowCount; n++) {
                    if (n == dataGridView1->RowCount - 1) sep = "";
                    afLine += dataGridView1->Rows[n]->Cells[0]->Value->ToString()+sep;
                }
                bdArr->Add(afLine);
             }
            else {
                bdArr->Add(line);
            }
        }
    }
    catch (Exception^ e) {
        MessageBox::Show(e->ToString());
    }
    finally {
        sr->Close();
    }
    StreamWriter^ sw = gcnew StreamWriter(path, false, Encoding::UTF8);
    try {
        for (int i = 0; i < bdArr->Count; i++) {
            String^ sep = "\n";
            if (i == bdArr->Count - 1) sep = "";
            sw->Write(bdArr[i] + sep);
        }
    }
    catch (Exception^ e) {
        MessageBox::Show(e->ToString());
    }
    finally {
        sw->Close();
    }
    return System::Void();
}
```