从父窗体中的 TPL 任务更新复杂子项

本文关键字:更新 复杂 任务 TPL 窗体 | 更新日期: 2023-09-27 18:33:54

我正在尝试使用一个显示耗时任务进度的表单升级我的 winforms 应用程序,但无论我做什么,表单都无法正常工作。这是我所拥有的:

  • 设置:

有一个带有一个按钮和以下代码的窗体 (Form1(:

public partial class Form1 : Form
{
    CancellationTokenSource cToken = null;
    public Form1()
    {
        InitializeComponent();
    }
    private void button1_Click(object sender, EventArgs e)
    {
        cToken = new CancellationTokenSource();
        using (Form2 form = new Form2())
        {
            form.Show(); //Shows the 'progress' form
            int i = 0;
            Task.Factory.StartNew(() =>
            {
                while (cToken.Token.IsCancellationRequested == false && i <= 5) //Runs the task until it is cancelled or has reached its end
                {
                    form.UpdateProgress(i); //Updates the 'progress' form
                    Thread.Sleep(500); //Waits simulating time consuming activity
                    i++;
                }
            }, cToken.Token, TaskCreationOptions.None, TaskScheduler.FromCurrentSynchronizationContext()).Wait();
        }
    }
}

然后,当运行耗时的操作时,Form1 会显示另一个窗体 (Form2(:

public partial class Form2 : Form
{
    public Form2()
    {
        InitializeComponent();
        progressBar1.Step = 1;
        progressBar1.Maximum = 6;
    }
    public void UpdateProgress(int i)
    {
            progressBar1.PerformStep();
            label1.Text = string.Format("Step {0} of 6", i);
    }
}

此表单具有进度条、标签(显示百分比(和取消按钮。

  • 预期行为:

当运行耗时的操作时,将显示 Form2(带有进度条的操作(,并且期望每次调用 UpdateProgress(( 时更新进度栏和标签文本。同时,不应或似乎阻止任何表单,以便用户可以随时取消耗时的任务。

  • 当前行为:

将显示 Form2,进度栏正确更新,但不显示其他控件,并且两个窗体都被阻止。

  • 附加信息:

我使用的是 C# 4.0,所以我无法使用 Progress,我想避免使用 BackgroundWorker 或事件(不是我不喜欢它们,这次我只想使用 TPL(。

  • 问题:

我有办法使用 TPL 实现我的目标吗?我已经在谷歌上搜索和阅读MSDN文档好几天了,但到目前为止还没有找到可行的解决方案。我在堆栈溢出上遇到了许多主题,但它们主要展示了如何在同一表单中异步更新进度条,我可以让它工作,但这不是我真正需要的。我很确定我错过了一些东西,但我无法弄清楚是什么。

从父窗体中的 TPL 任务更新复杂子项

代码使用 TaskScheduler.FromCurrentSynchronizationContext()UI 线程上启动一个新的 tash 然后对其调用 .Wait()

您需要同时删除.Wait()TaskScheduler.FromCurrentSynchronizationContext()。在子窗体的UpdateProgress内,应进行适当的Invoke调用以更新进度栏,或在此处 UI 线程上使用Task.StartNew来更新 UI。

还应考虑将 Microsoft.Bcl.Async 包添加到项目中,这将为 .NET 4.0 项目添加async/awaitProgress<T>支持。这将允许您大大清理代码。

.线程末端的 Wait(( 是导致同步行为的原因。