[C#] ProgressBarを非同期で更新する方法
C#でProgressBarを非同期で更新するには、通常、async
とawait
キーワードを使用して非同期メソッドを作成し、UIスレッドをブロックしないようにします。
例えば、Task.Run
を使用してバックグラウンドで処理を実行し、その進捗状況をIProgress<T>
インターフェースを介してUIスレッドに報告します。
Progress<T>クラス
を使用して、進捗の更新をUIスレッドで行うことができます。
これにより、UIがフリーズすることなく、ProgressBarがリアルタイムで更新されます。
ProgressBarを非同期で更新する方法
非同期メソッドの作成
非同期メソッドを作成することで、UIスレッドをブロックせずに長時間の処理を実行できます。
C#では、async
キーワードを使用して非同期メソッドを定義します。
以下は、非同期メソッドの基本的な構造です。
private async Task UpdateProgressBarAsync()
{
// 非同期処理をここに記述
}
このメソッド内で、時間のかかる処理を実行し、ProgressBarを更新することができます。
Task.Runを使用したバックグラウンド処理
Task.Runメソッド
を使用することで、バックグラウンドスレッドで処理を実行できます。
これにより、UIスレッドがフリーズすることを防ぎます。
以下は、Task.Run
を使用した例です。
private async Task UpdateProgressBarAsync()
{
await Task.Run(() =>
{
for (int i = 0; i <= 100; i++)
{
// 進捗状況を更新
System.Threading.Thread.Sleep(50); // 処理のシミュレーション
}
});
}
このコードでは、進捗状況を0から100まで更新し、各ステップで50ミリ秒の遅延を設けています。
IProgress<T>インターフェースの利用
IProgress<T>
インターフェースを使用することで、バックグラウンド処理からUIスレッドに安全に進捗状況を報告できます。
以下は、IProgress<int>
を使用した例です。
private async Task UpdateProgressBarAsync(IProgress<int> progress)
{
await Task.Run(() =>
{
for (int i = 0; i <= 100; i++)
{
// 進捗状況を報告
progress.Report(i);
System.Threading.Thread.Sleep(50); // 処理のシミュレーション
}
});
}
このメソッドでは、progress.Report(i)
を使用して進捗状況を報告しています。
Progress<T>クラスによるUIスレッドの更新
Progress<T>クラス
を使用すると、UIスレッドでの更新が簡単になります。
以下は、Progress<int>
を使用してProgressBarを更新する例です。
private async void StartButton_Click(object sender, EventArgs e)
{
Progress<int> progress = new Progress<int>(value =>
{
myProgressBar.Value = value; // ProgressBarの値を更新
});
await UpdateProgressBarAsync(progress); // 非同期メソッドを呼び出し
}
このコードでは、ボタンがクリックされたときにProgressBarが非同期で更新されます。
Progress<int>
を使用することで、UIスレッドでの安全な更新が実現されています。
サンプルプログラム
以下に、C# WindowsフォームアプリケーションでProgressBarを非同期で更新するサンプルプログラムを示します。
このプログラムでは、ボタンをクリックするとProgressBarが非同期で更新される仕組みを実装しています。
using System;
using System.Threading.Tasks;
using System.Windows.Forms;
public partial class MyForm : Form
{
public MyForm()
{
InitializeComponent();
}
private async void StartButton_Click(object sender, EventArgs e)
{
// Progress<int>を使用してUIスレッドでProgressBarを更新
Progress<int> progress = new Progress<int>(value =>
{
myProgressBar.Value = value; // ProgressBarの値を更新
});
await UpdateProgressBarAsync(progress); // 非同期メソッドを呼び出し
}
private async Task UpdateProgressBarAsync(IProgress<int> progress)
{
await Task.Run(() =>
{
for (int i = 0; i <= 100; i++)
{
// 進捗状況を報告
progress.Report(i);
System.Threading.Thread.Sleep(50); // 処理のシミュレーション
}
});
}
}
プログラムの解説
- フォームの初期化:
InitializeComponent();
メソッドでフォームのコンポーネントを初期化します。 - ボタンのクリックイベント:
StartButton_Click
メソッドでボタンがクリックされたときの処理を定義しています。 - Progress<int>の使用:
Progress<int>
を使用して、バックグラウンド処理からUIスレッドに進捗状況を報告します。 - 非同期処理:
UpdateProgressBarAsync
メソッド内で、Task.Run
を使用してバックグラウンドで処理を実行し、ProgressBarを更新します。
このプログラムを実行すると、ボタンをクリックすることでProgressBarが0から100まで非同期で更新される様子が確認できます。
応用例
複数のProgressBarを同時に更新する
複数のProgressBarを同時に更新するには、各ProgressBarに対して個別のProgress<int>
インスタンスを作成し、それぞれの進捗状況を報告します。
以下は、2つのProgressBarを同時に更新する例です。
private async void StartButton_Click(object sender, EventArgs e)
{
Progress<int> progressBar1Progress = new Progress<int>(value =>
{
progressBar1.Value = value; // 1つ目のProgressBarを更新
});
Progress<int> progressBar2Progress = new Progress<int>(value =>
{
progressBar2.Value = value; // 2つ目のProgressBarを更新
});
await Task.WhenAll(
UpdateProgressBarAsync(progressBar1Progress, 50), // 1つ目のProgressBar
UpdateProgressBarAsync(progressBar2Progress, 100) // 2つ目のProgressBar
);
}
private async Task UpdateProgressBarAsync(IProgress<int> progress, int delay)
{
await Task.Run(() =>
{
for (int i = 0; i <= 100; i++)
{
progress.Report(i);
System.Threading.Thread.Sleep(delay); // 処理のシミュレーション
}
});
}
このコードでは、2つのProgressBarがそれぞれ異なる速度で更新されます。
Task.WhenAll
を使用することで、両方の非同期処理を同時に実行しています。
非同期処理のキャンセル機能の実装
非同期処理をキャンセルするためには、CancellationToken
を使用します。
以下は、キャンセル機能を実装した例です。
private CancellationTokenSource cancellationTokenSource;
private async void StartButton_Click(object sender, EventArgs e)
{
cancellationTokenSource = new CancellationTokenSource();
var token = cancellationTokenSource.Token;
Progress<int> progress = new Progress<int>(value =>
{
myProgressBar.Value = value; // ProgressBarの値を更新
});
try
{
await UpdateProgressBarAsync(progress, token); // 非同期メソッドを呼び出し
}
catch (OperationCanceledException)
{
MessageBox.Show("処理がキャンセルされました。");
}
}
private async Task UpdateProgressBarAsync(IProgress<int> progress, CancellationToken token)
{
await Task.Run(() =>
{
for (int i = 0; i <= 100; i++)
{
token.ThrowIfCancellationRequested(); // キャンセルが要求された場合に例外をスロー
progress.Report(i);
System.Threading.Thread.Sleep(50); // 処理のシミュレーション
}
});
}
private void CancelButton_Click(object sender, EventArgs e)
{
cancellationTokenSource?.Cancel(); // キャンセル要求
}
このコードでは、CancellationTokenSource
を使用して非同期処理をキャンセルする機能を実装しています。
キャンセルボタンをクリックすると、進捗状況の更新が中断されます。
進捗状況をログに記録する
進捗状況をログに記録するには、進捗が更新されるたびにログファイルに書き込むことができます。
以下は、進捗状況をログに記録する例です。
private async Task UpdateProgressBarAsync(IProgress<int> progress)
{
await Task.Run(() =>
{
for (int i = 0; i <= 100; i++)
{
progress.Report(i);
LogProgress(i); // 進捗状況をログに記録
System.Threading.Thread.Sleep(50); // 処理のシミュレーション
}
});
}
private void LogProgress(int value)
{
// ログファイルに進捗状況を書き込む
using (StreamWriter writer = new StreamWriter("progress.log", true))
{
writer.WriteLine($"進捗状況: {value}% - {DateTime.Now}");
}
}
このコードでは、LogProgressメソッド
を使用して進捗状況をprogress.log
ファイルに記録しています。
進捗が更新されるたびに、現在の進捗状況とタイムスタンプがログに追加されます。
まとめ
この記事では、C# WindowsフォームアプリケーションにおけるProgressBarの非同期更新方法について詳しく解説しました。
非同期メソッドの作成や、Task.Run
を使用したバックグラウンド処理、IProgress<T>
インターフェースやProgress<T>クラス
を利用したUIスレッドの更新方法を学ぶことができました。
これらの知識を活用して、よりスムーズで応答性の高いアプリケーションを開発することが可能になりますので、ぜひ実際のプロジェクトに取り入れてみてください。