简体   繁体   中英

F# Event in class constructor

I'm currently learning F# by re-doing a simple mobile application I did in C# and Xamarin.forms which has forgoal to connect a user with facebook and get his profile and posts.

I almost finish everything but I'm blocked. To do my connection to the facebook API in C#, I used the Xamarin.Auth library and I want to reuse this library in F#.

Here is my code for my LoginPage ViewModel in C#:

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;
            }
        }
    }

My problem is to use Xamarin.Auth. I have to create a OAuth2Authenticator property that I initialize in the constructor of my class and then subscribe both EventHandler.Complete and.Error of this property to the two events OnAuthenticationCompleted and OnAuthenticationFailed in my class constructor and I've no idea how to do that in F#. Right now, my F# class looks like this:

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

But I don't know:

First, Where I should create my two methods OnAuthenticationCompleted and OnAuthenticationFailed, are they supposed to be methods of the class or not?

Second, How To subscribe my OAuth2Authenticator.Complete to OnAuthenticationCompleted and OAuth2Authenticator.Error to OnAuthenticationFailed methods in my class constructor

You can add even handlers to your authenticator object using the following syntax:

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)

If you want to be able to add and remove the handler, then you need to create an explicit EventHandler value first:

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)

That said, if you simply translate the C# code to F#, then you probably won't gain much in this case. Your logic is quite imperative and things like the mutable isLoading field and adding/removing of event handlers is going to make your F# code quite ugly. If you want to develop mobile applications with F#, then I would instead recommend looking at Fabulous , which lets you write nice functional code.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM