【发布时间】:2014-01-21 02:26:08
【问题描述】:
我正在使用Parse 作为应用程序的数据存储,并且我正在实现他们的Facebook Login 功能。 AFAIK,此登录方法与其他异步方法没有任何不同,因此希望它适用。
所以有一个 Login.xaml 页面,其中有一个“使用 Facebook 登录”按钮,点击此按钮会将您带到 FacebookLogin.xaml 页面,该页面仅包含 WebBrowser 根据链接的 Parse 文档的控件。在 FacebookLogin.xaml 上的ContentPanel.Loaded 中,我可以使用以下代码登录:
async void FacebookLogin()
{
try
{
user = await ParseFacebookUtils.LogInAsync(fbBrowser, new[] { "user_likes", "email" });
}
catch (OperationCanceledException oce)
{
// task was cancelled, try again
//task = null;
//FacebookLogin();
}
catch (Exception ex)
{
}
}
如果我真的登录了,它就可以工作,我可以将用户导航到下一页。当我让浏览器控件加载时出现问题(所以async方法是等待),然后点击Back按钮,然后返回再次访问 Facebook 登录页面。
当我这样做时,会抛出一个OperationCancelledException,但我不知道如何处理它。我试过的:
在
catch的OperationCanceledException中,将WebBrowser控件重新初始化为一个新控件。这没有效果。在同一个
catch,再次调用FacebookLogin(),重试。这也没有奏效。我也尝试过不使用
await并返回Task<ParseUser>,但我也不知道该怎么做。
我可以对取消异常做些什么,或者使用CancellationToken 来更好地处理这个问题?我只想正确处理取消操作,以便在用户按“返回”时重新加载 Facebook 登录页面。
解决方案:
好的,经过@JNYRanger 的大量指导,我想出了一个可行的解决方案。可能有更好的方法,但这似乎有效。这是我的 FacebookLogin.xaml 中的完整代码:
public partial class LoginFacebook : PhoneApplicationPage
{
Task<ParseUser> task;
CancellationTokenSource source;
public LoginFacebook()
{
InitializeComponent();
ContentPanel.Loaded += ContentPanel_Loaded;
}
async void ContentPanel_Loaded(object sender, RoutedEventArgs e)
{
try {
source = new CancellationTokenSource();
task = ParseFacebookUtils.LogInAsync(fbBrowser, new[] { "user_likes" }, source.Token);
await task;
// Logged in! Move on...
}
catch (Exception ex) { task = null; }
}
protected override void OnBackKeyPress(System.ComponentModel.CancelEventArgs e)
{
if (task != null) source.Cancel(false);
base.OnBackKeyPress(e);
}
}
所以基本上,当按下“返回”时,我使用CancellationToken 请求取消,这会引发异常。发生异常时,我将task 设置为null。现在,当重新导航到 FacebookLogin 页面时(之前没有登录),task 可以成功重新创建。
【问题讨论】:
-
小心,你仍然有
async void不是事件处理程序的方法。 -
我不确定如何在没有
async void的情况下使其工作,因为如果FacebookLogin()返回Task<ParseUser>,我必须在FacebookLogin()上使用await,这将要求我在ContentPanel_Loaded上使用async,这给了我另一个async void? -
实际上,根据您提供的文章,如果
async方法是一个事件处理程序(就像ContentPanel_Loaded那样),那是可以的。那么只制作ContentPanel_Loadedasync会是一个更好的解决方案吗? -
没错。这样就行了。对于非事件处理程序,而不是将它们设为
async void,您可以将它们设为async Task,其中任务不是通用的。由于您不需要ParseUser,因此您不需要使用Task<ParseUser>而不是返回 void 您只返回一个未包装的Task对象,您可以等待它以防万一出现错误。 -
如
public async Task FacebookLogin()
标签: c# asynchronous windows-phone-8 async-await cancellationtokensource