当所有任务完成时,我的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);
}

当所有任务完成时,我的UI得到更新

另一个答案就其本身而言是正确的。使用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 ;
        });