简体   繁体   English

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

[英]Calling synchronous methods asynchronously on the UI thread

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.我编写了一个 class 来检查 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 object 并检查 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.我正在寻找的是一种从 POP3 class 获得完成百分比或某种状态的方法,这反过来会更新 UI 并允许 UI 可用于执行其他任务。 I'll also need to call the EndInvoke method at some point in order to catch any exceptions thrown on the worker thread.我还需要在某个时候调用 EndInvoke 方法,以捕获工作线程上抛出的任何异常。

Any suggestions?有什么建议么?

Try using BackgroundWorker class, its was designed to do exactly what you need.尝试使用 BackgroundWorker class,它旨在满足您的需求。

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

Try the Backgroundworker class.试试Backgroundworker class。

Use a BackgroundWorker.使用 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.它还为您省去了在 UI 和后台 trheads 之间来回编组数据的麻烦,并且它允许进度通知和取消。

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.这将在数据到达时调用您的 FunctionToCallWhenDone。 You're also using ThreadPool which should be cheaper than creating own thread.您还使用 ThreadPool 应该比创建自己的线程便宜。 However, as Kurt Schelfthout noted you'll have to do something like uielement.Invoke(()=>{some code}) to change UI.但是,正如 Kurt Schelfthout 所指出的,您必须执行类似 uielement.Invoke(()=>{some code}) 之类的操作来更改 UI。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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