Skip to content

[Bug]: ReactiveUI.Maui On IOS and Android Binding is not working  #3520

Open
@RAMESHKUMAR502

Description

@RAMESHKUMAR502

Describe the bug 🐞

ReactiveUI.Maui On IOS and Android we are not able receive the command or Binding getting executed.
Below is the code Sinpet when i press login Button the command is not getting trigged once we port from xamarin to MAUI.

 public partial class LoginPage : ContentPage, IViewFor<LoginViewModel>
{
    /// <inheritdoc/>
    public LoginViewModel ViewModel { get; set; }

    /// <inheritdoc/>
    object IViewFor.ViewModel { get => this.ViewModel; set { this.ViewModel = (LoginViewModel)value; } }
    List<string> backimage = new List<string>();
    int pickedIndex = 0;

    /// <summary>
    /// Initializes a new instance of the <see cref="LoginPage"/> class.
    /// </summary>
    public LoginPage()
    {
        backimage.Add("portalui_1");
        backimage.Add("portalui_2_v2");
        backimage.Add("portalui_3_v2");
        backimage.Add("portalui_4_v2");
        backimage.Add("portalui_5_v2");
        backimage.Add("portalui_6_v2");
        backimage.Add("portalui_7");
        backimage.Add("portalui_8");
        Random random = new Random();
        pickedIndex = random.Next(backimage.Count);
        this.InitializeComponent();
        this.BindingContext = ViewModel;
        if (pickedIndex >= 0)
            this.BackgroundImageSource = backimage[pickedIndex];

        if (Device.RuntimePlatform == Device.Android)
            FaceID.Source = "fingerprint.svg";

        this.WhenActivated(disposables =>
        {
             this.BindCommand(
                    this.ViewModel,
                    vm => vm.LoginCommand,
                    v => v.LoginButton,
                    nameof(this.LoginButton.Clicked))
                .DisposeWith(disposables);

            this.Bind(
                    this.ViewModel,
                    vm => vm.EmailAddress,
                    v => v.EmailAddress.Text)
                .DisposeWith(disposables);

            this.Bind(
                   this.ViewModel,
                   vm => vm.Versionumber,
                   v => v.version.Text)
               .DisposeWith(disposables);

            this.Bind(
               this.ViewModel,
               vm => vm.IsFaceEnabledChecked,
               v => v.FaceEnableChecked.IsToggled)
           .DisposeWith(disposables);


            this.Bind(
               this.ViewModel,
               vm => vm.IsFaceSaved,
               v => v.FaceID.IsVisible)
           .DisposeWith(disposables);

            this.BindCommand(
                this.ViewModel,
                vm => vm.FaceClickCommand,
                v => v.FaceGesture)
            .DisposeWith(disposables);



            this.BindCommand(
                  this.ViewModel,
                  vm => vm.RestPasswordClickCommand,
                  v => v.RestPasswordGesture)
              .DisposeWith(disposables);

            this.BindCommand(
                this.ViewModel,
                vm => vm.ConcatusClickCommand,
                v => v.ContactUsGesture)
            .DisposeWith(disposables);



            this.BindCommand(
                  this.ViewModel,
                  vm => vm.ForgotUsernameClickCommand,
                  v => v.ForgotUsernameGesture)
              .DisposeWith(disposables);

            this.Bind(
                    this.ViewModel,
                    vm => vm.Enablefacemess,
                    v => v.EnbaleFace.Text)
                .DisposeWith(disposables);

            this.Bind(
                    this.ViewModel,
                    vm => vm.Password,
                    v => v.Password.Text)
                .DisposeWith(disposables);
        });
    }

    /// <inheritdoc/>
    protected override async void OnAppearing()
    {
        base.OnAppearing();
        if (this.Logo.IsVisible == false)
        {
            this.Logo.Opacity = 0;
            this.Logo.IsVisible = true;

            this.FormContainer.Opacity = 0;
            this.FormContainer.IsVisible = true;

            this.Logo.TranslationY = this.Logo.TranslationY + 200;
            await this.Logo.FadeTo(1, 700, Easing.CubicInOut);
            await this.Logo.TranslateTo(this.Logo.TranslationX, this.Logo.TranslationY - 200, 500, Easing.CubicInOut);
            await this.FormContainer.FadeTo(1, 700, Easing.CubicInOut);
        }
        try
        {
            if (this.ViewModel != null && Device.RuntimePlatform == Device.iOS)
            {
                await this.ViewModel.CheckForFingerprintAuthentication();
            }
#if TODOMAUI
            string latestVersionNumber = await CrossLatestVersion.Current.GetLatestVersionNumber();
            string installedVersionNumber = CrossLatestVersion.Current.InstalledVersionNumber;
            bool isupgradereq = false;
            if (Device.RuntimePlatform == Device.iOS)
            {

                if (Convert.ToInt32(installedVersionNumber) < Convert.ToInt32(latestVersionNumber))
                {
                    isupgradereq = true;
                }
            }
            else
            {
                if (Convert.ToDecimal(installedVersionNumber) < Convert.ToDecimal(latestVersionNumber))
                {
                    isupgradereq = true;
                }
            }

            if (isupgradereq == true)
            {
                await DisplayAlert("New Version", "There is a new version of this app available. Would you like to update now?", "Update");

                await CrossLatestVersion.Current.OpenAppInStore();
            }
#endif
        }
        catch (Exception ex)
        {

        }
    }

    void FaceEnableChecked_Toggled(System.Object sender, ToggledEventArgs e)
    {
        try
        {
            if (e.Value == false)
            {
                Preferences.Set("IsFaceEnabledChecked", e.Value.ToString());
            }
        }
        catch (Exception ex)
        {

        }
    }
}

 public class LoginViewModel : ReactiveObject, IEnableLogger, IRoutableViewModel
    {
        /// <inheritdoc/>
        public string UrlPathSegment => "Login";

        /// <inheritdoc/>
        public IScreen HostScreen { get; }

        private IAuthenticationService Service { get; }

        private string emailAddress;

        public string EmailAddress
        {
            get => emailAddress;
            set => this.RaiseAndSetIfChanged(ref emailAddress, value);
        }

        private string password;

        public string Password
        {
            get => password;
            set => this.RaiseAndSetIfChanged(ref password, value);
        }

        private string enablefacemess;

        public string Enablefacemess
        {
            get => enablefacemess;
            set => this.RaiseAndSetIfChanged(ref enablefacemess, value);
        }

        private string versionumber;

        public string Versionumber
        {
            get => versionumber;
            set => this.RaiseAndSetIfChanged(ref versionumber, value);
        }

        private bool isFaceEnabledChecked = true;

        public bool IsFaceEnabledChecked
        {
            get => isFaceEnabledChecked;
            set => this.RaiseAndSetIfChanged(ref isFaceEnabledChecked, value);
        }

        private bool isFaceSaved;

        public bool IsFaceSaved
        {
            get => isFaceSaved;
            set => this.RaiseAndSetIfChanged(ref isFaceSaved, value);
        }


        public ReactiveCommand<Unit, Unit> LoginCommand { get; }

        public ICommand RestPasswordClickCommand { get; set; }

        public ICommand FaceClickCommand { get; set; }

        public ICommand ConcatusClickCommand { get; set; }

        public ICommand ForgotUsernameClickCommand { get; set; }

        /// <summary>
        /// Initializes a new instance of the <see cref="LoginViewModel"/> class.
        /// </summary>
        /// <param name="hostScreen"></param>
        /// <param name="service"></param>
        public LoginViewModel(IScreen hostScreen, IAuthenticationService service = null)
        {
            this.HostScreen = hostScreen;
            this.Service = service ?? Locator.Current.GetService<IAuthenticationService>();
            Versionumber = "Version " + VersionTracking.CurrentVersion;
            if (Preferences.ContainsKey("IsFaceEnabledChecked"))
            {
                string IsFaceEnabled = Preferences.Get("IsFaceEnabledChecked", string.Empty);
                this.IsFaceEnabledChecked = Convert.ToBoolean(Preferences.Get("IsFaceEnabledChecked", string.Empty));
            }


            string EmailAdd = Preferences.Get("EmailAddress", string.Empty);
            string Passwd = Preferences.Get("Password", string.Empty);
            bool IsFaceChecked = false;
            if (Preferences.ContainsKey("IsFaceEnabledChecked"))
                IsFaceChecked = Convert.ToBoolean(Preferences.Get("IsFaceEnabledChecked", string.Empty));

            if (IsFaceChecked == true && !string.IsNullOrEmpty(EmailAdd) && !string.IsNullOrEmpty(Passwd))
                IsFaceSaved = true;


            this.RestPasswordClickCommand = ReactiveCommand.Create(() => this.RestPassword());
            this.ConcatusClickCommand = ReactiveCommand.Create(() => this.ConcatUS());
            this.ForgotUsernameClickCommand = ReactiveCommand.Create(() => this.ForgotUsername());

            this.FaceClickCommand = ReactiveCommand.Create(() => this.CheckForFingerprintAuthentication());

            var canLogin = this.WhenAnyValue(
                vm => vm.EmailAddress,
                vm => vm.Password,
                (emailAddress, password) => !string.IsNullOrEmpty(emailAddress) && !string.IsNullOrEmpty(password));
            this.LoginCommand = ReactiveCommand
                .Create(
                    () =>
                    {
                        Loginasync(this.EmailAddress, this.Password, true);
                    }, canLogin);

            this.LoginCommand
                .ThrownExceptions
                .Subscribe(ex =>
                {
                    UserDialogs.Instance.Alert(ex.Message, "Error");
                });

            if (Device.RuntimePlatform == Device.Android)
            {
                CheckForFingerprintAuthentication();
            }
        }

        private async Task Loginasync(string emailid, string password, bool isFirsttime = false)
        {
            try
            {
                var payload = new SignInPayload();
                payload.RememberMe = true;
                payload.UserName = emailid;
                payload.Password = password;

                UserDialogs.Instance.ShowLoading();

                this.Service
                    .SignIn(payload)
                    .SubscribeOn(RxApp.TaskpoolScheduler)
                    .ObserveOn(RxApp.MainThreadScheduler)
                    .Finally(() => UserDialogs.Instance.HideLoading())
                    .Subscribe(
                        content =>
                        {
                            Observable.FromAsync<string>(() => content.Content.ReadAsStringAsync())
                            .SubscribeOn(RxApp.TaskpoolScheduler)
                            .ObserveOn(RxApp.MainThreadScheduler)
                            .Subscribe(
                                async stringContent =>
                                {
                                    if (content.IsSuccessStatusCode)
                                    {
                                        IEnumerable<string> values;
                                        if (content.Headers.TryGetValues("Set-Cookie", out values))
                                        {
                                            App.cookiestring.Add(values);
                                        }

                                        Preferences.Set("EmailAddress", this.EmailAddress);
                                        Preferences.Set("Password", password);

                                        Preferences.Set("IsFaceEnabledChecked", this.IsFaceEnabledChecked.ToString());

                                        if (isFirsttime == true)
                                            await EnableFingerprintAuthentication();
#if TODOMAUI
                                        this.HostScreen.Router.NavigateAndReset.Execute(new HomeViewModel(this.HostScreen)).Subscribe();
#endif
                                    }
                                    else
                                    {
                                        UserDialogs.Instance.Alert(stringContent, "Error");
                                    }
                                },
                                e =>
                                {
                                    var apiException = (ApiException)e;
                                    UserDialogs.Instance.Alert(apiException.Content, "Error");
                                });
                        },
                        e =>
                        {
                            if (e is ApiException)
                            {
                                var apiException = (ApiException)e;
                                UserDialogs.Instance.Alert(apiException.Content, "Error");
                            }
                            else
                            {
                                UserDialogs.Instance.Alert(e.Message, "Error");
                            }
                        });
            }
            catch (Exception ex)
            {

            }
        }

        private async Task EnableFingerprintAuthentication()
        {
            if (this.IsFaceEnabledChecked == true)
            {
                var isFingerprintAvailable = await CrossFingerprint.Current.IsAvailableAsync(true);
                var authenticationType = await CrossFingerprint.Current.GetAuthenticationTypeAsync();

                string authenticationFailureMessage = authenticationType == Plugin.Fingerprint.Abstractions.AuthenticationType.Face ? "No Face ID Recognized." : "There are no fingerprints available.";
                if (isFingerprintAvailable)
                {
                    AuthenticationRequestConfiguration conf =
                    new AuthenticationRequestConfiguration("Authentication",
                                    "Authenticate access to your personal data");
                    var result = await CrossFingerprint.Current.AuthenticateAsync(conf);
                    if (result.Authenticated == false)
                    {

                    }
                }
            }


        }


        /// <summary>
        /// Checks for Finger Print Authentication
        /// </summary>
        /// <returns></returns>
        public async Task CheckForFingerprintAuthentication()
        {
            this.EmailAddress = Preferences.Get("EmailAddress", string.Empty);
            string Pwd = Preferences.Get("Password", string.Empty);

            var authenticationType = await CrossFingerprint.Current.GetAuthenticationTypeAsync();

            this.Enablefacemess = "Biometric ";



            this.IsFaceEnabledChecked = Convert.ToBoolean(Preferences.Get("IsFaceEnabledChecked", string.Empty));

            if (IsFaceEnabledChecked == true && !string.IsNullOrEmpty(this.EmailAddress) && !string.IsNullOrEmpty(Pwd))
            {
                var isFingerprintAvailable = await CrossFingerprint.Current.IsAvailableAsync(true);


                string authenticationFailureMessage = authenticationType == Plugin.Fingerprint.Abstractions.AuthenticationType.Face ? "No Face ID Recognized." : "There are no fingerprints available.";



                try
                {

                    if (isFingerprintAvailable)
                    {
                        AuthenticationRequestConfiguration conf =
                        new AuthenticationRequestConfiguration("Authentication",
                                        "Authenticate access to your personal data");
                        var result = await CrossFingerprint.Current.AuthenticateAsync(conf);


                        if (result.Authenticated)
                        {
                            this.EmailAddress = Preferences.Get("EmailAddress", string.Empty);
                            Pwd = Preferences.Get("Password", string.Empty);

                            if (!string.IsNullOrEmpty(this.EmailAddress) && !string.IsNullOrEmpty(Pwd))
                            {

                                await Loginasync(this.EmailAddress, Pwd, false); ;
                            }
                        }
                        else
                        {
                            UserDialogs.Instance.Alert("Unable to Access Biometric", "Error");
                        }
                    }
                    else
                    {
                        UserDialogs.Instance.Alert("Biometric is Not Supported", "Error");
                    }

                }
                catch (Exception exception)
                {
                    Debug.WriteLine("FingerPrint Exception" + exception);
                }
            }
        }

        private void ForgotUsername()
        {
#if TODOMAUI
            this.HostScreen.Router.NavigateAndReset.Execute(new ForgotusernameViewModel(this.HostScreen)).Subscribe();
#endif
        }

        private void RestPassword()
        {
#if TODOMAUI
            this.HostScreen.Router.NavigateAndReset.Execute(new ResetPasswordViewModel(this.HostScreen)).Subscribe();
#endif
        }

        private void ConcatUS()
        {
            //Webview
            //this.HostScreen.Router.NavigateAndReset.Execute(new ContactUSViewModel(this.HostScreen,false)).Subscribe();
            PhoneDialer.Open("8665903550");
        }
    }

Step to reproduce

  1. Go to '...'
  2. Click on '....'
  3. Scroll down to '....'
  4. See error

Reproduction repository

https://github.com/reactiveui/ReactiveUI

Expected behavior

This should happen...

Screenshots 🖼️

No response

IDE

No response

Operating system

Apple

Version

No response

Device

IOS

ReactiveUI Version

18.4.26

Additional information ℹ️

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions