views:

445

answers:

6

Hello

I have written a class that checks a POP3 account and I'd like it to execute on a thread other than the UI thread.

To do this, I've chosen the asynchronous route.

In order to get the result from pop3delegate.BeginInvoke(null,null) I need to call EndInvoke but doing this in the UI thread blocks rendering the UI unusable.

I could use the IAsyncResult object and check the IsComplete property, but this involves putting in a loop which checks and this in turn locks up the UI.

What I'm looking for is a way to get a percentage complete or some sort of a status from the POP3 class, which in turn updates the UI and also allows the UI to be usable to do other tasks. I'll also need to call the EndInvoke method at some point in order to catch any exceptions thrown on the worker thread.

Any suggestions?

+3  A: 

Try using BackgroundWorker class, its was designed to do exactly what you need.

Example and more details on msdn: http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx

Grzenio
I've had a read and it seems it's an event based reporting way of doing things, however, come to think about it, I could have events in my pop3 class and hook UI methods onto them to display the results.
Vince
A: 

Try the Backgroundworker class.

borisCallens
A: 

Try this article here

J Angwenyi
A: 

Use a BackgroundWorker. It also saves you the trouble of marshalling data back and forth between UI and background trheads, and it allows progress notifications and cancelling.

Kurt Schelfthout
A: 

Use event and threadpool

var asyncResult = pop3delegate.BeginInvoke(null,null);
ThreadPool.RegisterWaitForSingleObject(
    asyncResult.WaitHandle, FunctionToCallWhenDone, null, TimeSpan.Infinite, true);

This will call your FunctionToCallWhenDone when data arrives. You're also using ThreadPool which should be cheaper than creating own thread. However, as Kurt Schelfthout noted you'll have to do something like uielement.Invoke(()=>{some code}) to change UI.

A: 

You don't need to block or loop, you can simply pass a callback method (delegate) as the first parameter of your BeginInvoke call, here you can call EndInvoke process exceptions etc.

private delegate int LongRunningTaskHandler();
static void Main(string[] args) {
    LongRunningTaskHandler handler = LongRunningTask;
    handler.BeginInvoke(MyCallBack, null);
    Console.ReadLine();
}
private static void MyCallBack(IAsyncResult ar) {
    var result = (LongRunningTaskHandler)((AsyncResult) ar).AsyncDelegate;
    Console.WriteLine(result.EndInvoke(ar));
}
public static int LongRunningTask()
{
    Thread.Sleep(5000);
    return 42;
}
Dog Ears
The callback method won't give me a progress indicator, only that the task is complete. I need periodic checks.
Vince