【问题标题】:Updating a complex child from from a TPL task in the parent form从父表单中的 TPL 任务更新复杂子任务
【发布时间】:2014-12-09 21:36:52
【问题描述】:

我正在尝试使用可以显示耗时任务进度的表单升级我的 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();
        }
    }
}

那么还有另外一个表单(Form2)是Form1在运行耗时操作时显示的:

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 文档,但到目前为止还没有找到可行的解决方案。我在 stackoverflow 上遇到了很多主题,但它们主要展示了如何在同一个表单中异步更新进度条,我可以让它工作,但这不是我真正需要的。我很确定我错过了什么,但我不知道是什么。

【问题讨论】:

  • 您可以将Microsoft.Bcl.Async 包添加到您的项目中,以便为您的应用程序添加async/awaitProgress&lt;T&gt; 支持,即使它是.NET 4.0 并清理延续

标签: c# winforms asynchronous task-parallel-library


【解决方案1】:

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

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

您还应该考虑将Microsoft.Bcl.Async 包添加到您的项目中,这会为.NET 4.0 项目添加async/awaitProgress&lt;T&gt; 支持。这将允许您大量清理代码。

【讨论】:

  • 谢谢!您的回答让我意识到解决方案是多么明显。我已经删除了“wait()”和“TaskScheduler.FromCurrentSynchronizationContext()”,但后来我注意到 form2 很快就消失了。所以我走得更远,删除了'using(Form2 form = new Form2)'块,因为它在我的任务可以在其中做任何事情之前处理了表单(因此是Wait()),然后我添加了对form2的调用和现在一切都像魅力一样。
【解决方案2】:

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

【讨论】:

  • 我已经删除了 Wait() 部分并且已经解除了父表单的阻塞,子 (Form2) 表单仍然被阻塞并且这个表单上唯一呈现的对象仍然是进度条?我错过了什么吗?
  • 编辑:将任务作为参数传递给 Form2 并从表单本身启动它不是更好吗?
猜你喜欢
  • 1970-01-01
  • 2023-03-29
  • 2017-06-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多