[英]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:有几种解决方案可以摆脱这种情况:
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'sCanExecute
method returnsfalse
,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()
方法。
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属性值 = 1The 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.