アプリケーションのUIスレッドの応答性を維持しながら、ラベルのテキストを継続的に操作するにはどうすればよいですか?Visual Studio 2010でWindowsフォームアプリケーションを作成しています。また、vb.netまたはc#のいずれかで例を投稿できれば、非常にありがたいです。
2 に答える
を使用して、別のスレッドから実行する必要がありBeginInvoke
ます。これにより、UI スレッドの UI コントロールの状態が変更されます。
.NET Framework 4を使用している場合は、非同期タスクを使用できます。
このコードは、新しいスレッドで何かを開始します。
var myBackgroundTask = Task.Factory.StartNew(() => MyBackGroundMethod());
UIのコントロールはメインスレッドで作成されているため、ユーザーインターフェイス(UI)を更新するとします。別のスレッドから直接アクセスすると、クロススレッド例外がスローされます。ただし、バックグラウンドスレッドから新しいタスクを開始し、次のようにメインスレッドで実行するように指示することはできます。
private void MyMethod()
{
var uiTaskScheduler = TaskScheduler.FromCurrentSynchronizationContext();
var myBackgroundTask = Task.Factory.StartNew(() => MyBackGroundMethod(uiTaskScheduler));
}
private void MyBackGroundMethod(TaskScheduler uiTaskScheduler)
{
Task.Factory.StartNew(
() => { TextBox1.Text = "Hello from separate thread"; },
CancellationToken.None,
TaskCreationOptions.None,
uiTaskScheduler);
}
タスクが終了したときに何かをしたい場合は、次のような継続を使用できます。
var finishedTask = myBackgroundTask.ContinueWith(
x => Label1.Text = "Task 1 completed sucessfully",
CancellationToken.None,
TaskContinuationOptions.ExecuteSynchronously | TaskContinuationOptions.OnlyOnRanToCompletion,
uiTaskScheduler);
TaskContinuationOptionsに注意してください-エラーがない場合にのみ、またはキャンセルされた場合、キャンセルされていない場合などにのみ続行するように指定できます(さらに多く)。
長時間実行されているプロセスのキャンセルを許可する場合は、CancellationTokenを使用できます。
これは、バックグラウンドタスクを使用し、進行状況を更新し、キャンセルを許可し、終了、エラー、キャンセル、または完了したときにレポートする完全な例です。
これは、2つのボタン、1つのラベル、および1つのプログレスバーを備えたフォームです。それぞれStartButton、StopButton、ProgressBar、InformationLabelという名前です。
public partial class MainForm : Form
{
CancellationTokenSource cancelTokenSource;
public MainForm()
{
InitializeComponent();
}
private void StartButton_Click(object sender, EventArgs e)
{
InformationLabel.Text = "Task 1 running...";
var uiTaskScheduler = TaskScheduler.FromCurrentSynchronizationContext();
cancelTokenSource = new CancellationTokenSource();
this.StopButton.Enabled = true;
this.StartButton.Enabled = false;
var someWork = Task.Factory.StartNew(
() => { DoWork(uiTaskScheduler); },
cancelTokenSource.Token,
TaskCreationOptions.None,
TaskScheduler.Default);
var someWorkFinished = someWork.ContinueWith(
x => InformationLabel.Text = "Task 1 completed sucessfully",
CancellationToken.None,
TaskContinuationOptions.ExecuteSynchronously | TaskContinuationOptions.OnlyOnRanToCompletion,
uiTaskScheduler);
var someWorkErrored = someWork.ContinueWith(
x => InformationLabel.Text = "Task 1 Errored",
CancellationToken.None,
TaskContinuationOptions.OnlyOnFaulted,
uiTaskScheduler);
var someWorkCancelled = someWork.ContinueWith(
x => InformationLabel.Text = "Task 1 Cancelled",
CancellationToken.None,
TaskContinuationOptions.OnlyOnCanceled,
uiTaskScheduler);
var resultTasks = new List<Task>();
resultTasks.Add(someWorkFinished);
resultTasks.Add(someWorkErrored);
resultTasks.Add(someWorkCancelled);
Task.Factory.ContinueWhenAny(
resultTasks.ToArray(),
x => this.Reset(),
CancellationToken.None,
TaskContinuationOptions.None,
uiTaskScheduler);
}
private void Reset()
{
this.StopButton.Enabled = false;
this.StartButton.Enabled = true;
}
private void DoWork(TaskScheduler uiTaskScheduler)
{
for (int i = 0; i < 10; i++)
{
cancelTokenSource.Token.ThrowIfCancellationRequested();
Thread.Sleep(500);
i++;
// Update progress
Task.Factory.StartNew(
() => { UpdateProgress(ProgressBar, i * 10); },
CancellationToken.None,
TaskCreationOptions.None,
uiTaskScheduler);
}
}
private void UpdateProgress(ProgressBar progressBar, int i)
{
progressBar.Value = i;
}
private void StopButton_Click(object sender, EventArgs e)
{
cancelTokenSource.Cancel();
}
}