繁体   English   中英

使用TPL任务更新UI不会立即更新UI

[英]Using a TPL Task to update the UI does not immediately update the UI

我有一个.NET Windows窗体,它创建一个异步运行的任务。 该任务应该调用以更新其进度的UI。 它有效,但进度条只会因某种延迟而更新。

public partial class WaitDialog : Form
{
    private readonly TaskScheduler _uiScheduler = TaskScheduler.FromCurrentSynchronizationContext();

    private void ReportViewerWaitForm_Load(object sender, EventArgs e)
    {
        _asyncTask = Task.Factory.StartNew(Calculate(), _cancellationTokenSource.Token);   
        _asyncTask.ContinueWith(task => Close(), CancellationToken.None, TaskContinuationOptions.None, _uiScheduler);
    }

    private void Calculate()
    {
        UpdateProgressCount(0, 1000);

        for (int i = 0; i < 1000; i++)
        {
            // do some heavy work here
            UpdateProgressCount(i);
        }
    }

    private void UpdateUserInterface(Action action)
    {
        Task.Factory.StartNew(action, CancellationToken.None, TaskCreationOptions.None, _uiScheduler).Wait();
    }

    public void UpdateProgressCount(int count)
    {
        UpdateUserInterface(() => progressBar.Value = count);
    }

    public void UpdateProgressCount(int count, int total)
    {
        UpdateUserInterface(() =>
            {
                progressBar.Minimum = 0;
                progressBar.Maximum = total;
            });
        UpdateProgressCount(count);
    }

    private void WaitForm_FormClosing(object sender, FormClosingEventArgs e)
    {
        if (!_asyncTask.IsCompleted)
        {
            e.Cancel = true;
        }
    }
}

进度条正确设置,到表单关闭时,它的值设置为1000(或100%),但它不会以这种方式显示在UI上,它只显示大约50%的完成。

启动更新UI的任务,然后调用Wait(),但异步任务似乎在UI更新之前继续运行。 我假设这是因为UI线程本身做了某种BeginInvoke()来更新UI。

最终,当异步(繁重工作)任务完成时,UI不会完全更新,表单将关闭。 但UI任务Wait(),Application.DoEvents()或progressBar.Update()可以在返回繁重工作任务之前允许UI更新。

在UpdateProgressCount中,您可能希望改为使用进度调用表单。 这是更新事物的标准方法,而不是创建另一个任务。

另外,我相信通过等待在UI线程上运行的任务,您的后台线程将继续运行。 但我对那部分可能不正确。 无论如何,如果您使用应该解决问题的进度来调用您的表单。

不要为UI更新创建另一个任务,调用invoke方法来更新WinForm progressBar的状态。

更换

UpdateUserInterface(() => progressBar.Value = count)

if (progressBar.InvokeRequired) {
    progressBar.Invoke(() => progressBar.Value = count);
} else {
    progressBar.Value = count;
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM