テキストファイルを読み込み、外部アプリに自動入力するフォームアプリの機能の追加と変更

[前回の記事](https://qiita.com/Miyakepp_098/items/7913324160f706b14b92)のコードを変更、昨日の追加をしました。

## 主な変更点と追加項目
1 非同期処理の導入
2 処理の中断機能の追加
3 パスの生成方法の変更
4 入力の検証
5 メソッドの追加

### 1非同期処理の導入
変更前のコードでは、メソッドが同期的に動作していたが、改良後のコードでは非同期処理を導入した。
Thread.SleepをTask.Delayに置き換え、非同期的な待機を行うように変更した。

変更前
```c#:
private void button1_Click(object sender, EventArgs e)
{
    // ...
    Thread.Sleep(1000);
    // ...
}
```

変更後
```c#:
private async void button1_Click(object sender, EventArgs e)
{
    // ...
    await Task.Delay(1000, _cts.Token);
    // ...
}
```
### 2処理の中断機能の追加
CancellationTokenSourceを使用して、処理を中断する機能を追加。
フォームデザイナで停止ボタンを追加。クリックイベントハンドラ（buttonStop_Click）を追加し、ここで処理の中断要求を行う。
```c#:
private CancellationTokenSource _cts;

private void buttonStop_Click(object sender, EventArgs e)
{
    if (_cts != null)
    {
        _cts.Cancel();
    }
}
```

### 3パスの生成方法の変更
ファイルパスの生成にPath.Combineを使用するように変更した。


変更前
```c#:
string filePass = $@"{textBox1.Text}\{textBox2.Text}.txt";
```

変更後
```c#:
string filePass = Path.Combine(textBox1.Text, $"{textBox2.Text}.txt");
```
### 4入力の検証
テキストボックスが空でないか、ファイルが存在するかどうかの検証を追加。

```c#:
if (string.IsNullOrWhiteSpace(textBox1.Text) || string.IsNullOrWhiteSpace(textBox2.Text))
{
    MessageBox.Show("正しいパスを入力してください。");
    return;
}

if (!File.Exists(filePass))
{
    MessageBox.Show("指定されたファイルが存在しません。");
    return;
}
```

### 5メソッドの追加
SendDataToExcelという新しいメソッドを追加した。
```c#:
private void SendDataToExcel(string line, string key)
{
    string cleanedData = line.Replace(key, "").Trim();
    // ...
}
```


## 全コード
```c#:Form1
using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace TextFileInputOutput
{
    public partial class Form1 : Form
    {
        private CancellationTokenSource _cts;

        public Form1()
        {
            InitializeComponent();
        }

        private async void button1_Click(object sender, EventArgs e)
        {
            _cts = new CancellationTokenSource();

            try
            {
                Microsoft.VisualBasic.Interaction.AppActivate("Excel");

                if (string.IsNullOrWhiteSpace(textBox1.Text) || string.IsNullOrWhiteSpace(textBox2.Text))
                {
                    MessageBox.Show("正しいパスを入力してください。");
                    return;
                }

                string filePass = Path.Combine(textBox1.Text, $"{textBox2.Text}.txt");

                if (!File.Exists(filePass))
                {
                    MessageBox.Show("指定されたファイルが存在しません。");
                    return;
                }

                var lines = File.ReadAllLines(filePass);
                await Task.Delay(1000, _cts.Token);  // CancellationTokenを追加

                foreach (var line in lines)
                {
                    if (_cts.Token.IsCancellationRequested)
                    {
                        // 中断要求があった場合、処理を終了
                        return;
                    }

                    if (line.Contains("X="))
                    {
                        SendDataToExcel(line, "X=");
                    }
                    else if (line.Contains("Y="))
                    {
                        SendDataToExcel(line, "Y=");
                    }

                    await Task.Delay(100, _cts.Token);  // CancellationTokenを追加
                }
            }
            catch (OperationCanceledException)
            {
                // 処理が中断されたときの処理（必要に応じて）
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "エラー", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private void SendDataToExcel(string line, string key)
        {
            string cleanedData = line.Replace(key, "").Trim();

            if (key == "X=")
            {
                SendKeys.Send(cleanedData);
                SendKeys.Send("{TAB}");
            }
            else if (key == "Y=")
            {
                SendKeys.Send(cleanedData);
                SendKeys.Send("{ENTER}");
            }
        }

        private void button2_Click(object sender, EventArgs e)
        {
            DialogResult dr = folderBrowserDialog1.ShowDialog();
            if (dr == System.Windows.Forms.DialogResult.OK)
            {
                textBox1.Text = folderBrowserDialog1.SelectedPath;
            }
        }

        private void buttonStop_Click(object sender, EventArgs e)
        {
            if (_cts != null)
            {
                _cts.Cancel();
            }
        }
    }
}
```

## 最後に
SendKeys.Sendはアクティブなウィンドウにキーイベントを送信します。ユーザーが操作中に別のウィンドウをアクティブにした場合など、誤ったウィンドウやアプリケーションにキー入力が送られるリスクがあので注意しましょう！