简体   繁体   English

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

[英]ReactiveUI.Validation: this.IsValid() updated after ReactiveCommand is invoked

I'm starting out in using ReactiveUI.Validation.我开始使用 ReactiveUI.Validation。 When using this.IsValid() as the parameter for CanExecute in a ReactiveCommand.Create(), the IsValid is one user input "late".当在 ReactiveCommand.Create() 中使用 this.IsValid() 作为 CanExecute 的参数时,IsValid 是一个用户输入“延迟”。

This is a ViewModel.cs to reproduce the problem, for testing I bind it to a WPF TextBox:这是一个 ViewModel.cs 来重现问题,为了测试我将它绑定到 WPF TextBox:

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

This is the Console output I get (notice when the command is executed):这是我得到的控制台输出(执行命令时注意):

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 

This is the console output I would expect:这是我期望的控制台输出:

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 

Am I using it correctly?我是否正确使用它? Is there a way to force the validation before the InvokeCommand?有没有办法在 InvokeCommand 之前强制验证?

Thank you very much for your help!非常感谢您的帮助!

There are several solutions to get out of that situation:有几种解决方案可以摆脱这种情况:

Solution 1: Don't use InvokeCommand解决方案 1:不要使用InvokeCommand

The obvious one is not to use InvokeCommand if you want to bypass the validation under any circumstances.如果您想在任何情况下绕过验证,显而易见的是不要使用InvokeCommand Check the documentation of InvokeCommand() :检查InvokeCommand()文档

Hint InvokeCommand respects the command's executability.提示InvokeCommand尊重命令的可执行性。 That is, if the command's CanExecute method returns false , InvokeCommand will not execute the command when the source observable ticks.也就是说,如果命令的CanExecute方法返回false ,则InvokeCommand在源 observable 滴答时不会执行命令。

So you might want to call the SetMyProperty() method directly instead via the command.因此,您可能希望通过命令直接调用SetMyProperty()方法。

Solution 2: Delay the subscription on MyProperty解决方案 2:延迟订阅MyProperty

You can use the Observable.Delay() extension to wait for a small amount of time before reacting for the property change.您可以使用Observable.Delay()扩展在Observable.Delay()属性更改之前等待一小段时间。 That way you can "give enough time" for the IsValid() check to switch before doing your InvokeCommand call.这样,您就可以在执行InvokeCommand调用之前“ InvokeCommand足够的时间”让IsValid()检查进行切换。 The code might look like this:代码可能如下所示:

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

Solved by the good folks at GitHub: https://github.com/reactiveui/ReactiveUI.Validation/issues/92由 GitHub 上的好人解决: https : //github.com/reactiveui/ReactiveUI.Validation/issues/92

Copy of the post on GitHub: GitHub上帖子的副本:

If you place a call to this.WhenAnyValue below a call to this.ValidationRule, you'll get the following behavior:如果在调用 this.ValidationRule 下方调用 this.WhenAnyValue,您将获得以下行为:

IsValid = False有效 = 错误
Property value = 1属性值 = 1
Property value = 12属性值 = 12
Property value = 123属性值 = 123
IsValid = True有效 = 真
Property value = 1234属性值 = 1234
Entered method输入方法
Property value = 12345属性值 = 12345
Entered method输入方法
Property value = 1234属性值 = 1234
Entered method输入方法
IsValid = False有效 = 错误
Property value = 123属性值 = 123
Property value = 12属性值 = 12
Property value = 1属性值 = 1

The modified code looks as such:修改后的代码如下所示:

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

Both WhenAny and ValidationRule are using CurrentThreadScheduler since #97, so the call order matters now.从 #97 开始,WhenAny 和 ValidationRule 都在使用 CurrentThreadScheduler,所以现在调用顺序很重要。 Hopefully we will deploy the new version of the package to NuGet soon.希望我们很快将新版本的包部署到 NuGet。

It works with the new version 1.6.4 of ReactiveUI.Validation它适用于 ReactiveUI.Validation 的新版本 1.6.4

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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