从.net 2.0中的后台调用UI线程上的方法

时间:2013-02-21 08:48:58

标签: c# multithreading user-interface .net-2.0 monodevelop

我使用MonoDevelop(.net 2.0)开发iOS和Android应用程序。我使用BeginGetResponse和EndGetResponse在后台线程中异步执行webrequest。

IAsyncResult result = request.BeginGetResponse(new AsyncCallback(onLogin), state);

但是,回调onLogin似乎仍然在后台线程上运行,不允许我与UI交互。我该如何解决这个问题?

可以看到有Android和iOS特定解决方案,但需要跨平台解决方案。

编辑:从mhutch回答我已经走到了这一步:

IAsyncResult result = request.BeginGetResponse(o => {
            state.context.Post(() => { onLogin(o); });
        }, state);

其中州包含context类型为SynchronizationContext的{​​{1}}变量设置为SynchronizationContext.Current

它抱怨Post需要两个参数,第二个是Object state。插入state会出现错误

Argument `#1' cannot convert `anonymous method' expression to type `System.Threading.SendOrPostCallback' (CS1503) (Core.Droid)

2 个答案:

答案 0 :(得分:2)

Xamarin.iOS和Xamarin.Android都为GUI线程设置了SynchronizationContext

这意味着你从GUI线程获得SynchronizationContext.Current并将其传递给你的回调(例如通过状态对象或在lambda中捕获)。然后,您可以使用上下文的Post方法来调用主线程上的内容。

例如:

//don't inline this into the callback, we need to get it from the GUI thread
var ctx = SynchronizationContext.Current;

IAsyncResult result = request.BeginGetResponse(o => {
    // calculate stuff on the background thread
    var loginInfo = GetLoginInfo (o);
    // send it to the GUI thread
    ctx.Post (_ => { ShowInGui (loginInfo); }, null);
}, state);

答案 1 :(得分:0)

我不确定这是否适用于Mono,但我通常在WinForm应用程序上执行此操作。假设您要执行方法X()。然后:

public void ResponseFinished() {
    InvokeSafe(() => X()); //Instead of just X();
}

public void InvokeSafe(MethodInvoker m) {
    if (InvokeRequired) {
        BeginInvoke(m);
    } else {
        m.Invoke();
    }
}

当然,这是在Form类中。