ReactiveUI.验证:这个.调用ReactiveCommand后更新了IsValid()



我开始使用ReactiveUI。验证。使用时。IsValid((作为ReactiveCommand中CanExecute的参数。Create((,则IsValid是一个用户输入";迟到";。

这是一个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;
}
}

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

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。检查InvokeCommand():的文档

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

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

解决方案2:延迟订阅MyProperty

您可以使用Observable.Delay()扩展插件等待一小段时间,然后再对属性更改做出反应。这样你就可以";给予足够的时间";以便在进行InvokeCommand呼叫之前切换IsValid()检查。代码可能看起来像这样:

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:上的帖子副本

如果您对此进行了调用。WhenAnyValue低于对此的调用。ValidationRule,您将得到以下行为:

IsValid=False
属性值=1
IsValid=12
Property值=123
IsValid=True
输入方法
Property值=1234
进入方法
Propertyvalue=1234
输入方法
IsValid=False
Propertyvalue=123
Property值=12
Propertyvalue=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;
}
}

WhenAny和ValidationRule自#97以来都使用CurrentThreadScheduler,因此调用顺序现在很重要。希望我们能很快将新版本的软件包部署到NuGet。

它适用于新版本1.6.4的ReactiveUI。验证

最新更新