空気が良い日本の地区ランキング 2023年 で実装したWindowsフォームアプリは、処理中ダイアログをシンプルに実装していて、処理中ダイアログを早く実装したい場合の参考になります。
ソースコードは GitHub で公開しています。
処理中ダイアログ側

処理中ダイアログ側の処理は、StatusTextプロパティに渡された値を、txtStatusテキストボックスに表示しているだけです。
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | namespace WinFormsApp1 {     public partial class ProcessingDialog : Form     {         // txtStatusのテキストを設定・取得するためのプロパティ         public string StatusText         {             get { return txtStatus.Text; }             set { txtStatus.Text = value; }         }         public ProcessingDialog()         {             InitializeComponent();             this.ControlBox = false; // タイトルバーの制御ボックスを非表示に設定         }         private void ProcessingDialog_Shown(object sender, EventArgs e)         {             txtStatus.Text = string.Empty;         }     } } | 
処理中ダイアログを呼び出す側の実装

「CSVファイルをインポート」ボタンのクリックイベント処理から、ファイル操作/DB操作の細かい処理は除外し、確認/完了メッセージボックス表示、Task実行、処理中ダイアログ表示/非表示のみにすると下記になります。
・btnCsvFileImport_Clickボタンクリックイベントハンドラは asyncを加えて非同期メソッドへ変更。
・ファイルインポート/DB処理は、Task.Run()内に実装し、別スレッドで実行。
・別スレッドの task開始後、ProcessingDialog.ShowDialog()で処理中ダイアログを表示し、await task が終わるまで、処理中ダイアログは表示したままにしている。
・インポートしたファイルが増える度に、processingDialog.Invoke()を通して processingDialog.StatusTextプロパティに進行状況テキストを渡している。
・Task.Run()内の最後処理に、processingDialog.Invoke()を通して processingDialog.Close()を実行することで、ファイルインポート/DB処理が終わったら ProcessingDialog処理中ダイアログを閉じている。
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | private async void btnCsvFileImport_Click(object sender, EventArgs e) {     try     {         if (MessageBox.Show("CSVファイルのインポートを開始しますか?", "確認", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.No)             return;         var processingDialog = new ProcessingDialog();         var task = Task.Run(async () =>         {             try             {                 var csvFiles = Directory.GetFiles(txtWorkFolderPath.Text, "*.csv");                 int fileCnt = 0;                 foreach (var csvFilePath in csvFiles)                 {                     fileCnt++;                     // ファイルインポート処理、DB処理・・・ //                     processingDialog.Invoke(new Action(() =>                     {                         processingDialog.StatusText = $"処理済ファイル {fileCnt} / 全ファイル {csvFiles.Length}";// UIを更新                     }));                 }             }             finally             {                 processingDialog.Invoke(new Action(() =>                 {                     processingDialog.Close(); // バックグラウンド処理が完了したら閉じる                 }));             }         });         processingDialog.ShowDialog(); // 処理中ダイアログを表示         await task; // バックグラウンド処理が完了するまで待機         MessageBox.Show("CSVファイルのインポートが完了しました。", "完了", MessageBoxButtons.OK, MessageBoxIcon.Information);     }     catch (Exception ex)     {         MessageBox.Show($"{ex.Message}");     } } | 
「CSVファイルをインポート」ボタンのクリックイベント処理から、ファイル操作/DB操作の細かい処理を除外していない、元のソースコードは下記になります。
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 | private async void btnCsvFileImport_Click(object sender, EventArgs e) {     try     {         if (MessageBox.Show("CSVファイルのインポートを開始しますか?", "確認", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.No)             return;         var processingDialog = new ProcessingDialog();         var task = Task.Run(async () =>         {             try             {                 using (var conn = new SqlConnection(txtConnectionString.Text))                 {                     await conn.OpenAsync();                     // データは消す                     using (var cmd = new SqlCommand("TRUNCATE TABLE tImport_MeasurementData", conn))                     {                         await cmd?.ExecuteNonQueryAsync();                     }                     _DataTable.Clear();                     var csvFiles = Directory.GetFiles(txtWorkFolderPath.Text, "*.csv");                     int fileCnt = 0;                     foreach (var csvFilePath in csvFiles)                     {                         fileCnt++;                         using (var sr = new StreamReader(csvFilePath))                         {                             await sr.ReadLineAsync();// ヘッダ行を読み飛ばす                             string? line;                             while ((line = await sr.ReadLineAsync()) != null)                             {                                 var fields = line.Split(',');   // CSVの行をコンマで分割                                 fields[0] = fields[0].PadLeft(8, '0');                                 _DataTable.Rows.Add(fields);    // _DataTableに行を追加                             }                         }                         // 100ファイルごとまたは最後のファイルの場合、バッチ処理を実行                         if (fileCnt % 10 == 0 || fileCnt == csvFiles.Length)                         {                             using (var bulkCopy = new SqlBulkCopy(conn))                             {                                 bulkCopy.DestinationTableName = "tImport_MeasurementData";                                 // 列のマッピングを設定                                 bulkCopy.ColumnMappings.Add(0, "MeasurementStationCode");                                 bulkCopy.ColumnMappings.Add(1, "ImportDate");                                 bulkCopy.ColumnMappings.Add(2, "ImportTime");                                 bulkCopy.ColumnMappings.Add(3, "SO2_ppm");                                 bulkCopy.ColumnMappings.Add(4, "NO_ppm");                                 bulkCopy.ColumnMappings.Add(5, "NO2_ppm");                                 bulkCopy.ColumnMappings.Add(6, "NOx_ppm");                                 bulkCopy.ColumnMappings.Add(7, "CO_ppm");                                 bulkCopy.ColumnMappings.Add(8, "Ox_ppm");                                 bulkCopy.ColumnMappings.Add(9, "NMHC_ppmC");                                 bulkCopy.ColumnMappings.Add(10, "CH4_ppmC");                                 bulkCopy.ColumnMappings.Add(11, "THC_ppmC");                                 bulkCopy.ColumnMappings.Add(12, "SPM_mg_per_m3");                                 bulkCopy.ColumnMappings.Add(13, "PM25_ug_per_m3");                                 bulkCopy.ColumnMappings.Add(14, "SP_mg_per_m3");                                 bulkCopy.ColumnMappings.Add(15, "WD_16Dir");                                 bulkCopy.ColumnMappings.Add(16, "WS_m_per_s");                                 bulkCopy.ColumnMappings.Add(17, "TEMP_C");                                 bulkCopy.ColumnMappings.Add(18, "HUM_percent");                                 await bulkCopy.WriteToServerAsync(_DataTable);                                 _DataTable.Clear();                             }                             processingDialog.Invoke(new Action(() =>                             {                                 processingDialog.StatusText = $"処理済ファイル {fileCnt} / 全ファイル {csvFiles.Length}";// UIを更新                             }));                         }                     }                 }             }             finally             {                 processingDialog.Invoke(new Action(() =>                 {                     processingDialog.Close(); // バックグラウンド処理が完了したら閉じる                 }));             }         });         processingDialog.ShowDialog(); // 処理中ダイアログを表示         await task; // バックグラウンド処理が完了するまで待機         MessageBox.Show("CSVファイルのインポートが完了しました。", "完了", MessageBoxButtons.OK, MessageBoxIcon.Information);     }     catch (Exception ex)     {         MessageBox.Show($"{ex.Message}");     } } | 


コメント