![](/img/trans.png)
[英]How to wait in main form for an event fired and completed in another thread without blocking the UI
[英]How to wait for a return value from an event handler without blocking main UI thread
所以我有這個方法,它使用一個庫來生成一個外部網頁,允許用戶輸入他們的Facebook憑據進行驗證。 輸入后,我們將根據該用戶的帳戶創建配置文件並將其保存到數據庫中。 一旦我們將它保存到數據庫,我們期望一個布爾值來表示該帳戶是否是唯一的。 我們需要一些方法來等待數據庫在繼續執行之前完成所有工作。
我嘗試了幾種不同的方法,包括在新線程上完成所有工作(由於所有UI都需要在主線程上,因此無法工作)以及使用AutoResetEvent
等待auth.Completed
事件觸發。 但是當使用它時,它通常會阻塞線程,甚至不會為用戶顯示我們的外部網頁。
讓這更復雜的是試圖處理所有不同的事件而不是超越自己。 所以首先我們需要等待auth.Completed
觸發,然后從該事件內部我們需要等待異步request.GetResponseAsync().ContinueWith<Task<bool>>(async t => ...
event to finish,and終於等待數據庫完成其任務,並以某種方式將返回值一直推回到調用過程。
截至目前,此代碼將執行所有所需的功能,但將返回false,因為我們不等待任何事件觸發。
public bool LoginFacebook(bool isLinkedAccount)
{
#if __IOS__
UIKit.UIWindow window = UIKit.UIApplication.SharedApplication.KeyWindow;
UIKit.UIViewController viewController = window.RootViewController;
#endif
var auth = new OAuth2Authenticator(
clientId: "***********",
scope: "email",
authorizeUrl: new Uri("https://m.facebook.com/dialog/oauth/"),
redirectUrl: new Uri("http://www.facebook.com/connect/login_success.html")
);
#if __ANDROID__
Forms.Context.StartActivity(auth.GetUI(Android.App.Application.Context));
#elif __IOS__
if (viewController != null)
{
while (viewController.PresentedViewController != null)
viewController = viewController.PresentedViewController;
viewController.PresentViewController(auth.GetUI(), true, null);
}
#endif
// If authorization succeeds or is canceled, .Completed will be fired.
auth.AllowCancel = true;
auth.Completed += (sender, eventArgs) =>
{
#if __IOS__
viewController.DismissViewController(true, null);
#endif
if (eventArgs.IsAuthenticated)
{
var request = new OAuth2Request("GET", new Uri("https://graph.facebook.com/me"), null, eventArgs.Account);
request.GetResponseAsync().ContinueWith<Task<bool>>(async t =>
{
if (t.IsFaulted)
Console.WriteLine("Error: " + t.Exception.InnerException.Message);
else
{
try
{
string content = t.Result.GetResponseText();
Console.WriteLine(content);
JObject user = JsonConvert.DeserializeObject<JObject>(content);
Facebook profile = new Facebook();
profile.uuid = user["id"].ToString();
profile.firstname = user["first_name"].ToString();
profile.lastname = user["last_name"].ToString();
profile.email = user["email"].ToString();
profile.url = user["link"].ToString();
//Get picture
profile.photo = "https://graph.facebook.com/" + profile.uuid + "/picture?type=large";
if (!isLinkedAccount)
{
//App.AnimateLoading(LoadingImage, OverlayImage, LoadingMessage);
return await DatabaseInstance.InsertSocialProfile(SocialNetworks.Facebook, profile, true);
}
else
{
await DatabaseInstance.LinkSocialAccountToProfile(App.UserProfile, profile, SocialNetworks.Facebook);
return true;
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
return false;
});
}
};
return false;
}
您可以使用TaskCompletionSource
來表示一個等待的任務,在事件處理程序和其他async
方法之間進行協商。
為了簡潔和清晰,我從你的例子中刪除了所有#ifdef
代碼,只關注核心。 考慮到這一點,這是什么樣子:
public async bool LoginFacebook(bool isLinkedAccount)
{
var auth = new OAuth2Authenticator(
clientId: "***********",
scope: "email",
authorizeUrl: new Uri("https://m.facebook.com/dialog/oauth/"),
redirectUrl: new Uri("http://www.facebook.com/connect/login_success.html")
);
// If authorization succeeds or is canceled, .Completed will be fired.
auth.AllowCancel = true;
TaskCompletionSource<bool> completionSource = new TaskCompletionSource<bool>();
auth.Completed += (sender, eventArgs) =>
{
completionSource.SetResult(eventArgs.IsAuthenticated);
};
if (!(await completionSource.Task))
{
return false;
}
var request = new OAuth2Request("GET", new Uri("https://graph.facebook.com/me"), null, eventArgs.Account);
var t = await request.GetResponseAsync();
if (t.IsFaulted)
{
Console.WriteLine("Error: " + t.Exception.InnerException.Message);
return false;
}
try
{
string content = t.Result.GetResponseText();
Console.WriteLine(content);
JObject user = JsonConvert.DeserializeObject<JObject>(content);
Facebook profile = new Facebook();
profile.uuid = user["id"].ToString();
profile.firstname = user["first_name"].ToString();
profile.lastname = user["last_name"].ToString();
profile.email = user["email"].ToString();
profile.url = user["link"].ToString();
//Get picture
profile.photo = "https://graph.facebook.com/" + profile.uuid + "/picture?type=large";
if (!isLinkedAccount)
{
return await DatabaseInstance.InsertSocialProfile(SocialNetworks.Facebook, profile, true);
}
else
{
await DatabaseInstance.LinkSocialAccountToProfile(App.UserProfile, profile, SocialNetworks.Facebook);
return true;
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
return false;
}
}
當然,通過將此方法更改為async
方法,調用方現在可以在結果上異步等待,從而避免阻塞主線程。
當然,缺少一個好的, 最小的 , 完整的代碼示例 ,上面只是瀏覽器編輯的代碼。 我沒有編譯它,沒關系測試它。 但以上是一般的想法。 我假設您可以將該概念合並到實際代碼中。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.