【问题标题】:F# Event in class constructor类构造函数中的 F# 事件
【发布时间】:2023-03-27 18:20:02
【问题描述】:

我目前正在通过重新做一个简单的移动应用程序来学习 F#,该应用程序是我在 C# 和 Xamarin.forms 中完成的,该应用程序的目标是连接用户与 facebook 并获取他的个人资料和帖子。

我几乎完成了一切,但我被阻止了。为了在 C# 中连接到 facebook API,我使用了 Xamarin.Auth 库,我想在 F# 中重用这个库。

这是我在 C# 中的 LoginPage ViewModel 的代码:

public class LoginPageViewModel : BaseViewModel
    {
        private readonly INavigationService _navigationService;
        private readonly IConfiguration _config;
        private LoginLogic _loginLogic;
        public ICommand NavigateCommand { get; set; }
        public OAuth2Authenticator MyAuthenticator;
        public ICommand ConnectVerification { get; set; }
        public bool CanSkipPage { get; set; }
       


        public LoginPageViewModel(INavigationService navigationService, IConfiguration configuration)
        {
            if (navigationService == null) throw new ArgumentNullException("navigationService");
            _navigationService = navigationService;
            if (configuration == null) throw new ArgumentNullException("Configuration");
            _config = configuration;

            NavigateCommand = new RelayCommand(() => { _navigationService.NavigateTo(Locator.FacebookProfilePage); });
            MyAuthenticator = new OAuth2Authenticator(
                 _config.facebookAppId,
                 _config.scope,
                 new Uri(_config.facebookAuthUrl),
                 new Uri(_config.facebookRedirectUrl),
                 null);
            MyAuthenticator.Completed += OnAuthenticationCompleted;
            MyAuthenticator.Error += OnAuthenticationFailed;
            _loginLogic = SimpleIoc.Default.GetInstance<LoginLogic>();
            this.ConnectVerification = new AsyncCommand(() => TokenVerification());
        }

        public async Task TokenVerification()
        {
            IsLoading = true;
            if (await _loginLogic.CheckToken())
                NavigateCommand.Execute(null);
            IsLoading = false;
        }

        async void OnAuthenticationCompleted(object sender, AuthenticatorCompletedEventArgs e)
        {
            IsLoading = true;
            var authenticator = sender as OAuth2Authenticator;
            if (authenticator != null)
            {
                authenticator.Completed -= OnAuthenticationCompleted;
                authenticator.Error -= OnAuthenticationFailed;
            }
            await _loginLogic.SetTokenAsync(e.Account.Properties["access_token"]);
            loginLogic.SetTokenAsync(e.Account.Properties["access_token"]);
            NavigateCommand.Execute(null);
            IsLoading = false;
        }

        void OnAuthenticationFailed(object sender, AuthenticatorErrorEventArgs e)
        {
            var authenticator = sender as OAuth2Authenticator;
            if (authenticator != null)
            {
                authenticator.Completed -= OnAuthenticationCompleted;
                authenticator.Error -= OnAuthenticationFailed;
            }
        }
    }

我的问题是使用 Xamarin.Auth 。我必须创建一个 OAuth2Authenticator 属性,我在我的类的构造函数中初始化它,然后将此属性的 EventHandler .Complete 和 .Error 订阅到我的类构造函数中的两个事件 OnAuthenticationCompleted 和 OnAuthenticationFailed 我不知道该怎么做在 F# 中。 现在,我的 F# 类看起来像这样:

open Xamarin.Auth
open System
open GalaSoft.MvvmLight.Views

type LoginPageViewModel(navigationService: INavigationService) = 
    inherit ViewModelBase()

    let mutable isLoading = false
    let authenticator = new OAuth2Authenticator(config.facebookAppId,
                                                        config.scope, 
                                                        new Uri(config.facebookAuthUrl), 
                                                        new Uri(config.facebookRedirectUrl),
                                                        null)

    member this.MyAuthenticator
        with get() = authenticator
    
    member this.IsLoading
        with get() = isLoading 
        and set(value) =
            isLoading <- value
            base.NotifyPropertyChanged(<@ this.IsLoading @>)

    member this.TokenVerification() = 
        this.IsLoading <- true
        if loginLogic.CheckToken() 
        then 
            navigationService.NavigateTo("FacebookProfilePage")
        this.IsLoading <- false

但我不知道:

首先,我应该在哪里创建我的两个方法 OnAuthenticationCompleted 和 OnAuthenticationFailed,它们是否应该是类的方法?

第二,如何在我的类构造函数中订阅我的 OAuth2Authenticator.Complete 到 OnAuthenticationCompleted 和 OAuth2Authenticator.Error 到 OnAuthenticationFailed 方法

【问题讨论】:

    标签: c# f# c#-to-f#


    【解决方案1】:

    您可以使用以下语法将处理程序添加到您的身份验证器对象:

    let auth = OAuth2Authenticator("clientId", "scope", Uri("??"), Uri("??"))
    
    auth.Error.Add(fun err ->
      printfn "Error: %A" err)
    
    auth.Completed.Add(fun res -> 
      let at = res.Account.Properties.["access_token"]
      printfn "%A" at)
    

    如果您希望能够添加和删除处理程序,那么您需要先创建一个显式的EventHandler 值:

    let auth = OAuth2Authenticator("clientId", "scope", Uri("??"), Uri("??"))
    
    let handler = EventHandler<AuthenticatorCompletedEventArgs>(fun _ res ->
      let at = res.Account.Properties.["access_token"]
      printfn "%A" at)
    
    auth.Completed.AddHandler(handler)
    auth.Completed.RemoveHandler(handler)
    

    也就是说,如果您只是将 C# 代码转换为 F#,那么在这种情况下您可能不会获得太多收益。您的逻辑是非常必要的,可变的isLoading 字段和添加/删除事件处理程序之类的东西将使您的 F# 代码非常难看。如果你想用 F# 开发移动应用程序,那么我会推荐looking at Fabulous,它可以让你编写漂亮的函数式代码。

    【讨论】:

    • 感谢您的回答,我知道以这种方式使用 F# 并不是最好的,但我的目标是在两个不同的库中同时拥有 C# 和 F# 中我的应用程序的所有视图模型和逻辑,然后看看我是否可以轻松地从一个库切换到另一个库,这就是为什么我希望这两个库执行游戏代码,然后在未来结合 C# 和 F# 来构建我的 Xamarin.forms 应用程序,以便两者兼得。我仍然对你在这里给我的代码有疑问,EventHandler 是否应该是我的课程的一部分,如果是的话,我想在哪里做 auth.Completed.AddHandler(handler)
    猜你喜欢
    • 2017-06-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多