Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/xamarin/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 无法将ViewModel中的UIButton和UITextField与Xamarin iOS和ReactiveUI绑定_C#_Xamarin_Xamarin.ios_Reactive Programming_Reactiveui - Fatal编程技术网

C# 无法将ViewModel中的UIButton和UITextField与Xamarin iOS和ReactiveUI绑定

C# 无法将ViewModel中的UIButton和UITextField与Xamarin iOS和ReactiveUI绑定,c#,xamarin,xamarin.ios,reactive-programming,reactiveui,C#,Xamarin,Xamarin.ios,Reactive Programming,Reactiveui,我有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 GoBatu

我有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;
        }
    }
}
我的问题是字符串用户名和字符串密码可以绑定, usernameTextField.Text和passwordTextField.Text

但是UIButton和UITextField总是空的,它们没有绑定

我的任务是,每当用户在textField中键入字符时,我必须启用按钮;每当用户删除整个textField时,如果字符串为空,我必须再次禁用按钮,因此我需要UiButton来更改ViewModel中的背景色,但UiButton属性始终返回null

问题在哪里

如果有人能给我一点建议,我将非常高兴。 我对MVVM和ReactiveUi有点陌生

谢谢。

一些建议:

  • 视图模型不应引用任何与平台/视图相关的内容(去掉UITextField和UIButton成员)。视图模型是独立于平台的,因此可以重用和测试

  • 使用。它们自动处理按钮的启用/禁用。如果您查看此文档链接,您将发现基本上完全相同的示例代码/场景

  • 使用ReactiveViewController,这样您就不必担心自己实现ViewModel属性(您的版本应该使用RaiseAndSetIfChanged,如链接中所示)

public类LoginViewModel:ReactiveObject
{
公共登录视图模型()
{
var canLogin=this.whenyValue(
x=>x.UserName,
x=>x.密码,
(用户名,密码)=>!string.IsNullOrEmpty(用户名)和&!string.IsNullOrEmpty(密码));
LoginCommand=ReactiveCommand.CreateFromObservable(
LoginAsync,//返回IObservable的方法
可登录);
}
public ReactiveCommand登录命令{get;}
私有字符串\u用户名;
公共字符串用户名
{
获取{return\u userName;}
设置{this.RaiseAndSetIfChanged(ref{u用户名,值);}
}
私有字符串\u密码;
公共字符串密码
{
获取{return\u password;}
设置{this.RaiseAndSetIfChanged(ref_password,value);}
}
}

public分部类LogInViewController:ReactiveViewController
{      
UITapGestureRecognitor Singup手势;
公共登录查看控制器(IntPtr句柄):基本(句柄)
{
当激活时(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));
});
}
}
下面是一个示例,以及相应的示例项目,帮助您朝着正确的方向前进。我强烈推荐这本书,“如果你真的想变得精通。希望这有帮助。

一些建议:

  • 视图模型不应引用任何与平台/视图相关的内容(去掉UITextField和UIButton成员)。视图模型是独立于平台的,因此可以重用和测试

  • 使用。它们自动处理按钮的启用/禁用。如果您查看此文档链接,您将发现基本上完全相同的示例代码/场景

  • 使用ReactiveViewController,这样您就不必担心自己实现ViewModel属性(您的版本应该使用RaiseAndSetIfChanged,如链接中所示)

public类LoginViewModel:ReactiveObject
{
公共登录视图模型()
{
var canLogin=this.whenyValue(
x=>x.UserName,
x=>x.密码,
(用户名,密码)=>!string.IsNullOrEmpty(用户名)和&!string.IsNullOrEmpty(密码));
LoginCommand=ReactiveCommand.CreateFromObservable(
LoginAsync,//返回IObservable的方法
可登录);
}
public ReactiveCommand登录命令{get;}
私有字符串\u用户名;
公共字符串用户名
{
获取{return\u userName;}
设置{this.RaiseAndSetIfChanged(ref{u用户名,值);}
}
私有字符串\u密码;
公共字符串密码
{
获取{return\u password;}
设置{this.RaiseAndSetIfChanged(ref_password,value);}
}
}

public分部类LogInViewController:ReactiveViewController
{      
UITapGestureRecognitor Singup手势;
公共登录查看控制器(IntPtr句柄):基本(句柄)
{
当激活时(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中:

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

    }
视图和视图模型通过命令绑定进行交互


我希望这对你有帮助

好的,朋友,如果我理解正确,你可以这样做:

在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);

    }
视图和视图模型通过命令绑定进行交互


我希望这对你有帮助

您的ViewModel上不需要UIExtField和UIButton。您需要一个ReactiveCommand,ReactiveCommand定义了一个名为CanExecute的IObservable,通过将其与WhenyValue操作符相结合,您可以实现您的目标。但是我如何从ViewModel与ViewController的对象(如按钮和u)进行通信
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));
        });
    }
}
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));
        });
    }