简体   繁体   English

使用对话框执行长任务

[英]Long running task with dialog

I have this long running process and I want to display a form over the main app form explaining that it is long running with the ubiquitous circle progress bar. 我有一个长期运行的过程,我想在主应用程序表单上显示一个表单,解释该表单可以在无处不在的圆圈进度条上运行很长时间。 I just can't get anything to work properly. 我什么都无法正常工作。 The form doesn't show properly or animate the progress circle. 表单未正确显示或为进度圆设置动画。 If I try a different method as shown then the task doesn't finish! 如果我尝试使用如图所示的其他方法,则该任务无法完成!

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;
        }
    }

The long running form code looks like this: 长时间运行的表单代码如下所示:

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();
    }


}

The Application.DoEvents() is often misused. Application.DoEvents()通常被滥用。 On top of the common issue with the code re-entrancy via UI, you're also executing a busy-waiting loop . 除了通过UI进行代码重入的常见问题之外,您还在执行忙等待循环

You didn't specify where exactly you want to display the modal dialog. 您没有指定要在何处显示模式对话框。 As I understand it, the code might look like this: 据我了解,代码可能如下所示:

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();
        };
    }
}

This is just a skeletal implementation. 这只是一个骨架实现。 You should add some exception handling, cancellation and progress report logic for ProcessSusan . 您应该为ProcessSusan添加一些异常处理,取消和进度报告逻辑。 Here is a very good read on how to do that: Enabling Progress and Cancellation in Async APIs . 以下是有关如何执行此操作的非常好的读取: 在异步API中启用进度和取消

I've also answered a similar question recently. 我最近也回答了类似的问题 See if you can use the same approach. 看看你是否可以使用相同的方法。

It appears you are not taking advantage of what TPL actually offers. 看来你没有利用TPL实际提供的东西。

The following code snippet still blocks the GUI thread: 以下代码段仍然阻止GUI线程:

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

Because it will cycle so rapidly, the results will be undesirable. 因为它将如此迅速地循环,所以结果将是不希望的。 Replace it with the following: 将其替换为以下内容:

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

This will put the process on a different thread, and then invoke the second half of your method on the GUI thread once ProcessSusan() completes. 这将把进程放在不同的线程上,然后在ProcessSusan()完成后在GUI线程上调用方法的后半部分。

NOTE 注意

You must be the async keyword after private in the method definition. 您必须在方法定义中的private后面输入async关键字。

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

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