简体   繁体   中英

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. On top of the common issue with the code re-entrancy via UI, you're also executing a busy-waiting loop .

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 . Here is a very good read on how to do that: Enabling Progress and Cancellation in Async APIs .

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.

The following code snippet still blocks the GUI thread:

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.

NOTE

You must be the async keyword after private in the method definition.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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