2

我已经在我的 Windows 8 应用程序中实现了 Facebook C# SDK 客户端登录按钮,并让它在类似于提供的示例应用程序的模式下正常工作。我的问题是,在“Hello World”示例应用程序之外的任何东西中,登录按钮都需要能够同步其状态才能有用。

最明显的问题是,当导航离开带有登录按钮的页面,然后导航回该页面时,登录按钮根本没有状态(它没有会话,没有用户,不知道你实际上是登录等)。这个问题的一个更微妙的版本是,在一个真实的应用程序中,除非需要,否则您通常不希望强制用户向 Facebook 进行身份验证(因此,如果您从应用程序的先前会话中获得有效令牌,则用户被视为已登录,并且您不会在您的应用启动时提示他们再次登录)。但由于无法将任何状态传达给登录按钮控件,并且该控件似乎没有序列化/管理自己的状态,因此您无法执行任何操作。

我是 Windows 8 编程的新手,所以也许我错过了一些可以使这项工作发挥作用的神奇连接(我看到指示状态何时更改的事件和序列化状态的类,但我看不到任何方法将该状态放入 LoginButton,或以其他方式指示登录按钮序列化其状态)。并且 LoginButton 类被确定为似乎没有办法敲入状态 - 与会话状态相关的所有内容都是只读/私有的。

登录按钮(和其余控件)未在唯一重要的 SDK 示例(Scrumptious)中使用这一事实并不能真正激发人们对这些控件在现实世界中的准备情况的信心。

4

1 回答 1

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 恢复登录按钮状态。如果用户先前已登录,但令牌已过期(由于使用短期令牌,经常在启动时发生),我有一些附加逻辑可以自动重新验证。我也有逻辑在需要时重新加载 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 使用缓存提供程序获取会话状态并适当地初始化自身(至少在会话有效/未过期的情况下),这样它就可以在没有任何这些体操的情况下“神奇地”工作.

于 2013-08-17T20:50:13.390 回答