views:

2634

answers:

2

Hi all, I've got the following code:

void ReferenceManager_DoWork(object sender, DoWorkEventArgs e)
{
    try
    {

        // Get the raw data
        byte[] data = this.GetData(IvdSession.Instance.Company.Description, IvdSession.Instance.Company.Password);

        // Deserialize the list
        List<T> deseriaizedList = null;
        using (MemoryStream ms = new MemoryStream(data))
        {
            deseriaizedList = Serializer.Deserialize<List<T>>(ms);
        }

        // Convert the list to the Reference Interface
        List<IReference> referenceList = new List<IReference>();
        foreach (T entity in deseriaizedList)
        {
            IReference reference = (IReference)entity;
            referenceList.Add(reference);
        }

        e.Result = referenceList;

    }
    catch (WebException)
    {
        e.Result = null;
    }
}

The code is basically calling a delegate to a WebService method. Unfortunately, the main reason I used a background worker was to stop the UI freezing when loading the data. I've got a form that pops up saying please wait, click here to cancel.

On the click of cancel I call CancelAsync on the background worker. Now, as I'm not looping I cannot see a nice way of checking for a cancellation. The only option I can see is to have...

byte[] m_CurrentData;

...outside of the method and launch a new thread on the start of DoWork(..) that calls the webservice to populate m_CurrentData. I'd then need to perform a loop checking if cancelled or checking if m_CurrentData is no longer null.

Is there any better way of achieving a cancellation?

+1  A: 

Update

I've just checked the MSDN for DoWorkEventArgs and realised that my previous answer was wrong. There's the CancellationPending property on the BackgroundWorker which is set by by the call to CancelAsync (from the MSDN). Thus your DoWork method can become:

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
    // Do not access the form's BackgroundWorker reference directly.
    // Instead, use the reference provided by the sender parameter.
    BackgroundWorker bw = sender as BackgroundWorker;

    // Extract the argument.
    int arg = (int)e.Argument;

    // Start the time-consuming operation.
    e.Result = TimeConsumingOperation(bw, arg);

    // If the operation was canceled by the user, 
    // set the DoWorkEventArgs.Cancel property to true.
    if (bw.CancellationPending)
    {
        e.Cancel = true;
    }
}

Can you use this?

ChrisF
Hi, DoWork has e.Cancel which provides the cancellation notification. My method does not loop though, so there's no way to check if e.Cancel has changed to true.
GenericTypeTea
Ah - I read, but clearly didn't fully take in, that part of your question. I'll see if I can update the answer.
ChrisF
+2  A: 

The actual work seems to be done inside the this.GetData(...) method which is not shown. I gather it is calling a webservice. You probably should call the Abort() method on the proxy object to stop the client from waiting for the response. There is no point in calling CancelAsync(), just be sure to correctly check for errors in RunWorkerCompleted(). The easiest way is probably not to catch any exceptions in _DoWork(), but check the Result.Error property in Completed(). You should do that anyway.

Just to clarify, the CancelAsync() method is only useful to stop a loop inside DoWork(). You are not running a (meaningful) loop there, so another approach is needed.

Henk Holterman
So easy! Just call WebService.Abort() and catch the exception! Thanks for that!
GenericTypeTea