wpf cancel backgroundworker on application exits

2019-05-21 13:18发布

问题:

In my application I have a main windows and into it, in a frame I load a page. This page do a long time task when the user press a button. My problem is that when long task is being doing and the user presses the close button of the main window, the application seems to not finish because I am debugging it in VS2008 and I can see the stop button highlighted. If I want to finish I have to press stop button, the application doesn't stop the debugging automatically on application exit. I thought .NET stops automatically backgroundworkers on application exits but I am not sure after seeing this behaviour. I have tried to force and cancel background worker in unloaded event page with something like this:

    private void Page_Unloaded(object sender, RoutedEventArgs e)
    {
        // Is the Background Worker do some work?
        if (My_BgWorker != null && My_BgWorker.IsBusy)
        {
            //If it supports cancellation, Cancel It
            if (My_BgWorker.WorkerSupportsCancellation)
            {
                // Tell the Background Worker to stop working.
                My_BgWorker.CancelAsync();
            }
        }


    }

but with no success. After doing CancelAsync(), a few minutes after, I can see the backgroundworker finishes and raise RunWorkerCompleted and I can see the task is completed checking e.Cancelled argument in the event but after this event is exectued the application continues without exiting and I have no idea what is doing....

I set WorkerSupportsCancellation to true to support cancel at the begining.

I would apreciate all answers. Thanks.

回答1:

Cancellation is not automatic, your code in the DoWork event handler needs to handle the cancellation by checking the value of the CancellationPending property. Calling CancelAsync doesn't abort the thread, it merely sets CancellationPending to true...

For instance :

private void bgw_DoWork(object sender, DoWorkEventArgs e)
{
    while(!bgw.CancellationPending)
    {
        ...
    }
}


回答2:

I think Thomas Levesque pinpointed the issue.

On a general note: somewhere, some thread is still executing. You can try and find out what thread that is, by pausing the debug process (pause button, named "Break All"). At this point, the next code line executed should be highlighted. Also, you can use the Threads window (under Debug -> Windows) to see exactly which thread is still running, and where.



回答3:

Perfect Thomas, setting ShutdownMode to OnMainWindowClose as you said solved my problem. Now debugger stops correctly ;) Thanks very much for helping me.

What I did is:

       <Application 
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"                        
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         x:Class="GParts.App"
         StartupUri="WinMain.xaml"
         ShutdownMode="OnMainWindowClose">

                   <...>

        </Application>

Finally I would like to do one thing respect to backgroundworker in DoWork event in case an exception is thrown by some type of error: I hanlde errors inside it with a try catch clause and into catch I do:

        catch (Exception ex)
        {
            e.Result = ex.Message;               
        }

When backgroundworker finishes by an exception I want in RunWorkerCompleted to detect it with e.Error and show it. So what I do in RunWorkerCompleted is:

        if (e.Cancelled)
        {
            // Cancelled

        }
        else if (e.Error != null)
        {
            // Exception Thrown
            // Here I want to show the message that produced the exception in DoWork
            // event. If I set  e.Result = ex.Message in DoWork event, is e.Error here
            // containing ex.Message?


        }
        else
        {
            // Completed);
        }

Is e.Error in RunWorkerCompleted containing ex.Message?

Thanks.