我已经在我的Windows 8应用程序中实现了Facebook C#SDK客户端LoginButton,并使其在类似于提供的示例应用程序的模式下正常工作。我的问题是,除了某种“Hello World”示例应用程序之外,登录按钮需要能够同步其状态以便有用。
最明显的问题是,当使用登录按钮导航离开页面,然后导航回该页面时,登录按钮根本没有状态(它没有会话,没有用户,不知道你'实际登录等)。这个问题的一个更微妙的版本是,在真实的应用程序中,您通常不希望强制用户向Facebook进行身份验证,除非它是必需的(因此,如果您的应用程序的上一个会话中有一个有效的令牌,则该用户被视为已登录,并且当您的应用程序启动时,您不会提示他们再次登录)。但由于没有办法将任何状态传递给登录按钮控件,并且控件似乎没有序列化/管理自己的状态,所以你不能这样做。
我是Windows 8编程的新手,所以也许我错过了一些可以使其工作的神奇连接(我看到指示状态发生变化的事件和序列化状态的类,但我不知道看到任何方式将该状态转换为LoginButton,或以其他方式指示登录按钮序列化其状态)。并且LoginButton类被固定到似乎没有办法打破状态 - 与会话状态相关的所有内容都是只读/私有。
登录按钮(以及其他控件)未用于唯一的非平凡SDK示例(Scrumptious)这一事实并不能真正激发人们对这些控件的实际准备情况的信心。
答案 0 :(得分:6)
好的,好像我要回答我自己的问题;)
LoginButton在内部使用FacebookSessionClient登录/注销,而FacebookSessionClient实际上使用适当的FacebookSessionCacheProvider序列化会话状态。到目前为止,非常好。
然后,技巧是在加载页面时将任何现有会话状态设置为按钮。我原先确信这是不可能的,因为CurrentSession和CurrentUser的LoginButton属性是只读的。但经过进一步审查后,我发现我实际上可以使用SetValue通过其依赖属性设置这些值。
我使用适当的事件处理程序从LoginButton跟踪会话和用户状态,如下所示:
private void OnSessionStateChanged(object sender, Facebook.Client.Controls.SessionStateChangedEventArgs e)
{
if (e.SessionState == Facebook.Client.Controls.FacebookSessionState.Opened)
{
App.CurrentSession = this.loginButton.CurrentSession;
}
else if (e.SessionState == Facebook.Client.Controls.FacebookSessionState.Closed)
{
App.CurrentSession = null;
// The control signals when user info is set (handled in OnUserInfoChanged below), but not when it
// is cleared (probably a bug), so we clear our reference here when the session ends.
//
App.CurrentUser = null;
}
}
private void OnUserInfoChanged(object sender, UserInfoChangedEventArgs e)
{
App.CurrentUser = this.loginButton.CurrentUser;
}
在页面加载时,我从缓存中获取会话状态(因此这在启动应用程序时,在恢复应用程序时以及从另一页面导航回此页面时都有效)并且我使用SetValue适当地恢复LoginButton状态。我有一些额外的逻辑,如果用户以前登录过,则自动重新验证,但是有一个过期的令牌(由于使用短期令牌而经常在启动时发生)。我还有逻辑在需要时重新加载CurrentUser。结果是登录按钮在所有三种情况下都具有正确的状态。
private async void navigationHelper_LoadState(object sender, LoadStateEventArgs e)
{
this.loginButton.ApplicationId = Constants.FacebookAppId;
App.CurrentSession = FacebookSessionCacheProvider.Current.GetSessionData();
if ((App.CurrentSession != null) && (App.CurrentSession.Expires <= DateTime.UtcNow))
{
// User was previously logged in, but session expired. Log them in again...
App.CurrentSession = await App.FacebookSessionClient.LoginAsync(Constants.FacebookPermissions);
}
if (App.CurrentSession != null)
{
this.loginButton.SetValue(LoginButton.CurrentSessionProperty, App.CurrentSession);
if (App.CurrentUser == null)
{
FacebookClient client = new FacebookClient(App.CurrentSession.AccessToken);
dynamic result = await client.GetTaskAsync("me");
App.CurrentUser = new GraphUser(result);
}
}
if (App.CurrentUser != null)
{
this.loginButton.SetValue(LoginButton.CurrentUserProperty, App.CurrentUser);
}
}
我认为正确的解决方案是让LoginButton使用缓存提供程序获取会话状态并适当地初始化自身(至少在会话有效/未到期的情况下),这样它就可以“神奇地”工作而不会这些体操。