在UI线程上异步调用同步方法

时间:2021-04-04 20:57:29

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.

我编写了一个检查POP3帐户的类,我希望它在UI线程以外的线程上执行。

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.

为了从pop3delegate.BeginInvoke(null,null)获得结果,我需要调用EndInvoke,但是在UI线程块中执行此操作会导致UI无法使用。

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.

我可以使用IAsyncResult对象并检查IsComplete属性,但这涉及放入一个检查的循环,这反过来会锁定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.

我正在寻找的是一种从POP3类获得完成百分比或某种状态的方法,这反过来更新UI并允许UI可用于执行其他任务。我还需要在某个时刻调用EndInvoke方法,以便捕获在工作线程上抛出的任何异常。

Any suggestions?

5 个解决方案

#1


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

尝试使用BackgroundWorker类,它的设计完全符合您的需求。

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

有关msdn的示例和更多详细信息:http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx

#2


Try the Backgroundworker class.

尝试Backgroundworker类。

#3


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.

使用BackgroundWorker。它还为您节省了在UI和后台传输之间来回编组数据的麻烦,并且它允许进度通知和取消。

#4


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.

这将在数​​据到达时调用FunctionToCallWhenDone。你也使用ThreadPool,它应该比创建自己的线程便宜。但是,正如Kurt Schelfthout所说,你必须做一些像uielement.Invoke(()=> {some code})这样的东西来改变UI。

#5


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.

您不需要阻塞或循环,只需传递一个回调方法(委托)作为BeginInvoke调用的第一个参数,在这里您可以调用EndInvoke进程异常等。

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

#1


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

尝试使用BackgroundWorker类,它的设计完全符合您的需求。

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

有关msdn的示例和更多详细信息:http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx

#2


Try the Backgroundworker class.

尝试Backgroundworker类。

#3


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.

使用BackgroundWorker。它还为您节省了在UI和后台传输之间来回编组数据的麻烦,并且它允许进度通知和取消。

#4


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.

这将在数​​据到达时调用FunctionToCallWhenDone。你也使用ThreadPool,它应该比创建自己的线程便宜。但是,正如Kurt Schelfthout所说,你必须做一些像uielement.Invoke(()=> {some code})这样的东西来改变UI。

#5


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.

您不需要阻塞或循环,只需传递一个回调方法(委托)作为BeginInvoke调用的第一个参数,在这里您可以调用EndInvoke进程异常等。

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