【问题标题】:Long running task with dialog带对话框的长时间运行任务
【发布时间】:2014-01-11 22:56:47
【问题描述】:

我有这个长时间运行的进程,我想在主应用程序表单上显示一个表单,说明它使用无处不在的圆形进度条长时间运行。我只是无法让任何东西正常工作。表单没有正确显示或动画进度圈。如果我尝试如图所示的不同方法,则任务不会完成!

private void lbMethods_SelectedIndexChanged(object sender, EventArgs e)
    {
        switch (lbMethods.SelectedIndex)
        {
            case (int)Methods.none:
                break;
            case (int)Methods.Susan:
                Log("Starting Susan Edge Detection");
                Progressing("Please wait for edge detection");
                Task t = new Task(() => ProcessSusan());
                while (!t.IsCompleted)
                {
                    Application.DoEvents();
                }
                Log("Detection Finished");
                Progressing("", false);
                break;
            default:
                break;
        }
    }

    private void ProcessSusan()
    {
        Susan s = new Susan(CurrentImage);
        List<IntPoint> corners = s.GetCorners();
    }

    private void Progressing(string message, bool Show = true)
    {

        if (Show)
        {
            lblStatus.Text = message;
            Progress.Style = ProgressBarStyle.Continuous;
        }
        else
        {
            lblStatus.Text = "...";
            Progress.Style = ProgressBarStyle.Blocks;
        }
    }

长时间运行的表单代码如下所示:

public partial class FrmProcessing : Form
{
    public string description { get; set; }

    public FrmProcessing(string description)
    {
        InitializeComponent();
        lblDescription.Text = description;

    }

    // Let the calling method close this form.
    public void Close()
    {

        this.Close();
    }


}

【问题讨论】:

  • 你确定这样做有什么意义吗?如果某件事始终花费很长时间,那么用“花费很长时间”的微调器来娱乐用户是没有意义的。他们在几次后收到消息,停止查看并启动纸牌。用一个 NotifyIcon 来适应它。或者只是确保他们从不觉得他们必须等待,这太糟糕了。
  • 你在哪里创建 FrmProcessing?
  • @Hans.. 这是一个糟糕的建议。这需要“训练”用户知道应用程序没有被锁定。

标签: c# winforms task-parallel-library


【解决方案1】:

Application.DoEvents() 经常被误用。除了通过 UI 重新输入代码的常见问题之外,您还执行了busy-waiting loop

您没有指定要在何处显示模态对话框。据我了解,代码可能如下所示:

private void lbMethods_SelectedIndexChanged(object sender, EventArgs e)
{
    switch (lbMethods.SelectedIndex)
    {
        case (int)Methods.none:
            break;
        case (int)Methods.Susan:
            Log("Starting Susan Edge Detection");
            Progressing("Please wait for edge detection");

            var dialog = new FrmProcessing();
            dialog.StartTaskFunc = () =>
                Task.Run(ProcessSusan);
            dialog.ShowDialog();

            Log("Detection Finished");
            Progressing("", false);
            break;
        default:
            break;
    }
}

public partial class FrmProcessing : Form
{
    public Func<Task> StartTaskFunc { get; set; }

    public string description { get; set; }

    public FrmProcessing(string description)
    {
        InitializeComponent();
        lblDescription.Text = description;

        // async event handler for "Form.Load"
        this.Load += async (s, e) =>
        {
            // start the task and await it
            await StartTaskFunc();
            // close the modal form when the task finished
            this.Close();
        };
    }
}

这只是一个骨架实现。您应该为ProcessSusan 添加一些异常处理、取消和进度报告逻辑。这是一个很好的阅读方法:Enabling Progress and Cancellation in Async APIs

我最近也回复了a similar question。看看你是否可以使用相同的方法。

【讨论】:

  • 执行此操作时,任务开始,但 GUI 不加载/显示。
  • @AdamReed,请随时发布一个最小的独立代码来重现问题。
【解决方案2】:

您似乎没有利用 TPL 实际提供的功能。

以下代码 sn -p 仍然阻塞 GUI 线程:

Task t = new Task(() => ProcessSusan());
while (!t.IsCompleted)
{
  Application.DoEvents();
}

因为它会如此快速地循环,所以结果将是不可取的。将其替换为以下内容:

await Task.Run(()=>ProcessSusan());

这会将进程放在不同的线程上,然后在 ProcessSusan() 完成后在 GUI 线程上调用方法的后半部分。

注意

您必须是方法定义中private 之后的async 关键字。

【讨论】:

  • 这不能解决lbMethods_SelectedIndexChanged 被触发而await Task.Run(()=&gt;ProcessSusan()) 尚未完成的情况。 OP 最肯定不希望多个ProcessSusan 并行运行。它也没有回答如何显示模态表单。
  • @Noseratio,实际上在某种程度上确实如此。前面的代码不会将 UI 线程的控制权返回给用户。用户根本无法让多个ProcessSusans 并行运行。第一步是将工作推到另一个线程上。安德鲁建议。下一步是创建一个TaskCancelationToken 传递给Task.Run,以便UI 线程可以杀死现有的运行。
  • @Aron,这就是我没有否决这个答案的原因。但是,这不是 OP 所要求的,是不是:我想在主应用程序表单上显示一个表单,说明它与无处不在的圆形进度条长时间运行。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-08-13
  • 2022-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-03
  • 2013-02-25
  • 2013-07-08
相关资源
最近更新 更多