当所有任务完成时,我的UI得到更新
本文关键字:UI 更新 我的 任务 完成时 | 更新日期: 2023-09-27 18:14:16
看到我下面的代码,并告诉我什么是错误的,我的UI得到更新时,所有的任务完成,但按代码它应该更新标签值时,我的例程是由任务调用。在我的代码中需要修改什么
说,例如当DoSomething1被调用时,label3需要在用户之前更新和反映。
private void button1_Click(object sender, EventArgs e)
{
TaskScheduler uiScheduler = TaskScheduler.FromCurrentSynchronizationContext();
var token = Task.Factory.CancellationToken;
var tasks = new[]
{
Task.Factory.StartNew( DoSomething1,token,TaskCreationOptions.None, uiScheduler),
Task.Factory.StartNew(DoSomething2,token,TaskCreationOptions.None, uiScheduler),
Task.Factory.StartNew(DoSomething3,token,TaskCreationOptions.None, uiScheduler)
};
Task.WaitAll(tasks);
//var things = Task.WhenAll(tasks);
int x=0;
}
public void DoSomething1()
{
//this.label3.BeginInvoke(new Action(() =>
//{
// this.label3.Text = "DoSomething1 -- " + System.Threading.Thread.CurrentThread.ManagedThreadId;
//}));
this.label3.Text = "DoSomething1 -- " + System.Threading.Thread.CurrentThread.ManagedThreadId;
System.Threading.Thread.Sleep(1000);
}
public void DoSomething2()
{
//this.label4.BeginInvoke(new Action(() =>
//{
// this.label4.Text = "DoSomething2 -- " + System.Threading.Thread.CurrentThread.ManagedThreadId;
//}));
this.label4.Text = "DoSomething2 -- " + System.Threading.Thread.CurrentThread.ManagedThreadId;
System.Threading.Thread.Sleep(1000);
}
public void DoSomething3()
{
//this.label5.BeginInvoke(new Action(() =>
//{
// this.label5.Text = "DoSomething3 -- " + System.Threading.Thread.CurrentThread.ManagedThreadId;
//}));
this.label5.Text = "DoSomething3 -- " + System.Threading.Thread.CurrentThread.ManagedThreadId;
System.Threading.Thread.Sleep(1000);
}
另一个答案就其本身而言是正确的。使用FromCurrentSynchronizationContext()
会导致正在使用的调度器始终使用当前线程来运行任务。即UI线程。任务应该使用Task.Run()
运行,而不使用特定的调度器(它将默认使用线程池调度器)。BeginInvoke()
是正确访问Label
对象的一种选择。
然而,在我看来,最好修复所有的代码,使其在当前的async
/await
范式中更习惯。例如:
private async void button1_Click(object sender, EventArgs e)
{
// Your original example didn't show how you used this value,
// so I don't have anything in this example that uses it. But you
// would probably want to pass it to the "DoSomething..." methods
// so that those methods can then pass the token to whatever async
// operation they are actually doing. See additional comment below.
var token = Task.Factory.CancellationToken;
var tasks = new[]
{
DoSomething1(),
DoSomething2(),
DoSomething3()
};
await Task.WhenAll(tasks);
int x=0;
}
public async Task void DoSomething1()
{
this.label3.Text = "DoSomething1 -- " + System.Threading.Thread.CurrentThread.ManagedThreadId;
// replace with `Task.Run()` or whatever already-asynchronous
// operation you need/want. Likewise in the other methods.
// Don't forget to pass the CancellationToken to these methods,
// and then on to whatever tasks you actually are running.
await Task.Delay(1000);
}
public async Task DoSomething2()
{
this.label4.Text = "DoSomething2 -- " + System.Threading.Thread.CurrentThread.ManagedThreadId;
await Task.Delay(1000);
}
public async Task DoSomething3()
{
this.label5.Text = "DoSomething3 -- " + System.Threading.Thread.CurrentThread.ManagedThreadId;
await Task.Delay(1000);
}
虽然我不熟悉TaskScheduler
,但它看起来像是在UI线程上调度所有任务。
不使用调度程序,然后做你的UI更新使用如下:
var threadId = System.Threading.Thread.CurrentThread.ManagedThreadId;
this.BeginInvoke(() => {
this.label3.Text = "DoSomething1 -- " + threadId ;
});