问题描述
我开始使用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一起使用