ReactiveUI.Validation:调用ReactiveCommand后更新this.IsValid

问题描述

我开始使用ReactiveUI.Validation。在ReactiveCommand.Create()中使用this.IsValid()作为CanExecute的参数时,IsValid是一个用户输入的“ late”。

这是一个重现该问题的viewmodel.cs,为了进行测试,我将其绑定到WPF文本框:

public class viewmodel : ReactiveValidationObject<viewmodel>
{
    private readonly ReactiveCommand<string,Unit> Command;

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

    public viewmodel()
    {
        Command = ReactiveCommand.Create<string>(x => SetMyProperty(x),this.IsValid());

        this
            .WhenAnyValue(x => x.MyProperty)
            .Do(x => Console.WriteLine("Property value = " + x))
            .InvokeCommand(Command);

        this.ValidationRule(
            viewmodel => viewmodel.MyProperty,x => !string.IsNullOrEmpty(x) && x.Length > 3,"Enter a value");

        this.IsValid()
            .Subscribe(x => Console.WriteLine("IsValid = " + x));
    }

    private Unit SetMyProperty(string value)
    {
        Console.WriteLine("Entered method");
        return Unit.Default;
    }
}

这是我得到的控制台输出(执行命令时注意):

Property value = 1  
Property value = 12  
Property value = 123  
Property value = 1234  
IsValid = True  
Property value = 12345  
Entered method  
Property value = 1234  
Entered method  
Property value = 123  
Entered method  
IsValid = False  
Property value = 12  
Property value = 1 

这是我期望的控制台输出

Property value = 1  
Property value = 12  
Property value = 123  
Property value = 1234  
IsValid = True  
Entered method  
Property value = 12345  
Entered method  
Property value = 1234  
Entered method  
Property value = 123  
IsValid = False  
Property value = 12  
Property value = 1 

我正确使用了吗?有没有办法在InvokeCommand之前强制验证?

非常感谢您的帮助!

解决方法

有几种解决方案可以摆脱这种情况:

解决方案1:不要使用InvokeCommand

很明显,如果您想在任何情况下都绕过验证,则不要使用InvokeCommand。检查documentation of InvokeCommand()

提示 InvokeCommand尊重命令的可执行性。也就是说,如果命令的CanExecute方法返回false,则在源可观察到的滴答声中,InvokeCommand将不会执行命令。

因此,您可能想直接通过命令调用SetMyProperty()方法。

解决方案2:延迟MyProperty上的订阅

您可以使用Observable.Delay()扩展名等待一小段时间,然后再对属性更改做出反应。这样,您可以在致电IsValid()之前为“ InvokeCommand”切换提供“足够的时间”。代码可能看起来像这样:

this.WhenAnyValue(x => x.MyProperty)
    .Delay(TimeSpan.FromMilliseconds(100))
    .Do(x => Console.WriteLine("Property value = " + x))
    .InvokeCommand(Command);
,

由GitHub上的好人解决:https://github.com/reactiveui/ReactiveUI.Validation/issues/92

该帖子在GitHub上的副本:

如果您对此this.ValidationRule的调用下调用this.WhenAnyValue,则会出现以下行为:

IsValid = False
属性值= 1
属性值= 12
属性值= 123
IsValid = True
属性值= 1234
输入的方法
属性值= 12345
输入的方法
属性值= 1234
输入的方法
IsValid = False
属性值= 123
属性值= 12
属性值= 1

修改后的代码如下:

    public class ViewModel : ReactiveValidationObject<ViewModel>
    {
        private readonly ReactiveCommand<string,Unit> Command;
    
        private string _myProperty;
        public string MyProperty
        {
            get => _myProperty;
            set => this.RaiseAndSetIfChanged(ref _myProperty,value);
        }
    
        public ViewModel()
        {
            Command = ReactiveCommand.Create<string>(x => SetMyProperty(x),this.IsValid());
    
            this.ValidationRule(
                viewModel => viewModel.MyProperty,x => !string.IsNullOrEmpty(x) && x.Length > 3,"Enter a value");
            
            // The call to WhenAny is now placed below a call to ValidationRule.
            this.WhenAnyValue(x => x.MyProperty)
                .Do(x => Console.WriteLine("Property value = " + x))
                .InvokeCommand(Command);
    
            this.IsValid()
                .Subscribe(x => Console.WriteLine("IsValid = " + x));
        }
    
        private Unit SetMyProperty(string value)
        {
            Console.WriteLine("Entered method");
            return Unit.Default;
        }
    }

从#97开始,WhenAny和ValidationRule都在使用CurrentThreadScheduler,因此呼叫顺序现在很重要。希望我们会尽快将新版本的软件包部署到NuGet。

它与ReactiveUI.Validation的新版本1.6.4一起使用

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...