Не могу связать UIButton и UITextField в ViewModel с помощью Xamarin-iOS и ReactiveUI - PullRequest
0 голосов
/ 04 июля 2018

У меня есть класс LoginViewController

// This file has been autogenerated from a class added in the UI designer.

using System;
using System.Collections.Generic;
using Foundation;
using UIKit;
using System.Linq;
using System.Reactive;
using ReactiveUI;
using GoBatumi.IOS.ViewModels;

namespace GoBatumi.IOS
{
    public partial class LogInViewController : ReactiveViewController,IViewFor<LoginViewModel>
    {      
        UITapGestureRecognizer SingUpGesture;
        public LogInViewController (IntPtr handle) : base (handle)
        {
            this.WhenActivated(d =>
            {
                d(this.Bind(ViewModel, vm => vm.UserName, vm => vm.userNameTextField.Text));
                d(this.Bind(ViewModel, vm => vm.Password, vm => vm.passwordTextField.Text));
                d(this.Bind(ViewModel, vm => vm.LoginButton, vm => vm.logInButton));
                d(this.Bind(ViewModel, vm => vm.PasswordTextField, vm => vm.passwordTextField));
            });
        }

        private void MakeViewModelBinding(){
        }

        public override void ViewDidLayoutSubviews(){
            base.ViewWillLayoutSubviews();   
        }

        LoginViewModel _viewModel;
        public LoginViewModel ViewModel 
        {
            get => _viewModel ?? new LoginViewModel();
            set => _viewModel = value;
        }
        object IViewFor.ViewModel 
        {
            get => ViewModel;
            set => ViewModel = (LoginViewModel)value; 
        }

        public override void ViewDidLoad(){
            base.ViewDidLoad();
        }

        private void ShouldChangeViewSettings(bool enable){
            passwordTextField.Enabled = enable;
            logInButton.Enabled = enable;         
            if (enable)
                logInButton.Alpha = 0.99f;
            else
                logInButton.Alpha = 0.4f;
        }
    }

    public class TestUser
    {
        public string UserName{
            get;
            set;
        }

        public string Password{
            get;
            set;
        }
    }
}

Также у меня есть класс LoginViewModel

using System;
using System.Diagnostics;
using ReactiveUI;
using UIKit;

namespace GoBatumi.IOS.ViewModels
{
    public class LoginViewModel : ReactiveObject
    {
        public LoginViewModel()
        {
        }

        private string _userName;
        public string UserName
        {
            get => _userName;
            set
            {
                this.RaiseAndSetIfChanged(ref _userName, value);
                var result = string.IsNullOrEmpty(_userName);

                ShouldChangeViewSettings(result);
            }
        }


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

        }

        private UIButton _loginButton;
        public UIButton LoginButton
        {
            get => _loginButton;
            set => this.RaiseAndSetIfChanged(ref _loginButton, value);
        }

        private UITextField _passwordTextField;
        public UITextField PasswordTextField
        {
            get => _passwordTextField;
            set => this.RaiseAndSetIfChanged(ref _passwordTextField, 
        }

    }
}

Моя проблема в том, что имя пользователя строки и пароль строки могут связываться, usernameTextField.Texts и passwordTextField.Text

Но это UIButton и UITextField всегда равны нулю, они не связаны.

Моя задача состоит в том, чтобы всякий раз, когда пользователь вводит символ в textField, я должен включить кнопку, и всякий раз, когда пользователь удаляет поле целого текста и, если строка пуста, я должен снова отключать кнопку, поэтому мне нужен UiButton для изменения цвета фона из ViewModel, но UIButtonProperty всегда возвращает ноль.

Где проблема?

Я буду очень рад, если кто-нибудь даст мне совет. Я немного новичок в MVVM и в ReactiveUi.

Спасибо.

Ответы [ 2 ]

0 голосов
/ 05 июля 2018

Хорошо, друг, если я правильно понимаю, вы можете сделать что-то вроде этого:

В вашей ViewModel:

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

    public LoginViewModel()
    {
        //this operator does the magic, when UserName and Password be different than empty your button
        //will be enabled
        var canLogin = this.WhenAnyValue(x => x.UserName, x=> x.Password, 
                                        (user,password) => !string.IsNullOrWhiteSpace(user) && !string.IsNullOrWhiteSpace(password));

        LoginCommand = ReactiveCommand.CreateFromTask<Unit, Unit>(async _ =>
        {
            //Your login logic goes here..
            return Unit.Default;
        }, canLogin);

    }

И по вашему мнению

 public LogInViewController (IntPtr handle) : base (handle)
    {
        this.WhenActivated(d =>
        {
            d(this.Bind(ViewModel, vm => vm.UserName, vm => vm.userNameTextField.Text));
            d(this.Bind(ViewModel, vm => vm.Password, vm => vm.passwordTextField.Text));
            d(this.BindCommand(this.ViewModel,vm => vm.LoginCommand,v => v.LoginButton));
        });
    }

ваше представление и ваша модель представления взаимодействуют посредством привязки команд.

Надеюсь, это поможет вам.

0 голосов
/ 05 июля 2018

Несколько предложений:

  • Ваши модели представлений никогда не должны ссылаться на что-либо, связанное с платформой / представлением (избавьтесь от членов UITextField и UIButton). Модели представлений не зависят от платформы, поэтому их можно использовать повторно и тестировать.

  • Использовать ReactiveCommands . Они обрабатывают включение / отключение кнопки автоматически. Если вы перейдете по этой ссылке на документацию, вы найдете в точности тот же пример кода / сценария.

  • Используйте универсальную версию ReactiveViewController, чтобы вам не пришлось беспокоиться о реализации свойств ViewModel самостоятельно (ваша версия должна была использовать RaiseAndSetIfChanged, как вы увидите в ссылке).

...

public class LoginViewModel : ReactiveObject
{
    public LoginViewModel()
    {
        var canLogin = this.WhenAnyValue(
            x => x.UserName,
            x => x.Password,
            (userName, password) => !string.IsNullOrEmpty(userName) && !string.IsNullOrEmpty(password));
        LoginCommand = ReactiveCommand.CreateFromObservable(
            LoginAsync, // A method that returns IObservable<Unit>
            canLogin);
    }

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

    private string _userName;
    public string UserName
    {
        get { return _userName; }
        set { this.RaiseAndSetIfChanged(ref _userName, value); }
    }

    private string _password;
    public string Password
    {
        get { return _password; }
        set { this.RaiseAndSetIfChanged(ref _password, value); }
    }
}

...

public partial class LogInViewController : ReactiveViewController<LoginViewModel>
{      
    UITapGestureRecognizer SingUpGesture;

    public LogInViewController (IntPtr handle) : base (handle)
    {
        this.WhenActivated(d =>
        {
            d(this.Bind(ViewModel, vm => vm.UserName, v => v.userNameTextField.Text));
            d(this.Bind(ViewModel, vm => vm.Password, v => v.passwordTextField.Text));
            d(this.BindCommand(ViewModel, vm => vm.LoginCommand, v => v.logInButton));
        });
    }
}

Вот строго документированная ViewModel вместе с соответствующим примером проекта, который поможет вам двигаться в правильном направлении. И я настоятельно рекомендую книгу « Вы, я и ReactiveUI », если вы действительно хотите стать опытным. Надеюсь, это поможет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...