Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/279.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# ReactiveUI.Validation:调用ReactiveCommand后更新此.IsValid()_C#_Reactiveui - Fatal编程技术网

C# ReactiveUI.Validation:调用ReactiveCommand后更新此.IsValid()

C# ReactiveUI.Validation:调用ReactiveCommand后更新此.IsValid(),c#,reactiveui,C#,Reactiveui,我开始使用ReactiveUI.Validation。在ReactiveCommand.Create()中将此.IsValid()用作CanExecute的参数时,IsValid是一个用户输入“late” 这是一个ViewModel.cs,用于重现问题,为了进行测试,我将其绑定到WPF文本框: public class ViewModel : ReactiveValidationObject<ViewModel> { private readonly ReactiveComm

我开始使用ReactiveUI.Validation。在ReactiveCommand.Create()中将此.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  
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
尊重命令的可执行性。也就是说,如果命令的
CanExecute
方法返回
false
InvokeCommand
将不会在源可观察到的滴答声时执行命令

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

解决方案2:延迟订阅
MyProperty
在响应属性更改之前,可以使用扩展等待一小段时间。这样,您就可以在执行
InvokeCommand
调用之前为
IsValid()
检查切换“留出足够的时间”。代码可能如下所示:

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

由GitHub的好人解决:

GitHub上帖子的副本:

如果在调用this.ValidationRule的下面调用this.whenyValue,您将获得以下行为:

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

修改后的代码如下所示:

public类ViewModel:ReactiveValidationObject
{
私有只读反应命令;
私有字符串_myProperty;
公共字符串MyProperty
{
get=>\u myProperty;
set=>this.RaiseAndSetIfChanged(ref\u myProperty,value);
}
公共视图模型()
{
Command=ReactiveCommand.Create(x=>SetMyProperty(x),this.IsValid());
这个.ValidationRule(
viewModel=>viewModel.MyProperty,
x=>!string.IsNullOrEmpty(x)和&x.Length>3,
“输入值”);
//对WhenAny的调用现在位于对ValidationRule的调用下面。
this.whenyValue(x=>x.MyProperty)
.Do(x=>Console.WriteLine(“属性值=“+x))
.InvokeCommand(命令);
这是有效的()
.Subscribe(x=>Console.WriteLine(“IsValid=“+x”);
}
私有单元SetMyProperty(字符串值)
{
Console.WriteLine(“输入方法”);
返回单位。默认值;
}
}
WhenAny和ValidationRule都从#97开始使用CurrentThreadScheduler,因此调用顺序现在很重要。希望我们能很快将新版本的包部署到NuGet


它与新版本1.6.4的ReactiveUI配合使用。验证

解决方案1:我需要某种验证,以防止在模型中输入无效值。也许我做错了。解决方案2:它可以使用100ms、10ms,但不能使用1ms。它也适用于油门。这是一个稳健的解决方案吗?我一直认为允许任务同步的延迟是个坏主意。谢谢你的反馈@是的,使用延迟/限制来同步线程不是同步线程的正确方法,这是一个懒惰的解决方案。我只是没有找到一个不同的方法来解决这个问题,但我肯定有一个。对于解决方案1部分:您可以在
SetMyProperty
方法中使用
ValidationContext.IsValid
属性来检查该方法是否在验证上下文有效时调用(如果无效则引发异常)。当我访问
ValidationContext.IsValid
时,它也不表示我的属性的已刷新验证状态(就像
this.IsValid()
)。所以它不起作用。我试图在
ReactiveUI.Validation
的GitHub中找到一个方法,该方法将在
InvokeCommand
之前强制执行验证,但还没有成功。@antoine扩展方法
IsValid()
定义为
IObservable
,因此在更改有效标志时会通知您。我尝试将它与属性更改上的
combinelateest()
一起使用,以仅在它为
true
时才作出反应,但它对我来说并不太有效。也许你可以检查一下你是否可以使用由
IsValid()
返回的可观测值。我扫描了大多数Rx操作符,但我找不到什么可以做到这一点。我暂时不回答这个问题,看看是否有更多的想法。这个问题看起来像是用户不断修改属性,而验证规则事件最终落在后面的问题。您可能可以通过在可观察的属性(调用InvokeCommand()的属性)上使用Throttle()来解决此问题,例如
this.whenyValue(x=>x.MyProperty).Throttle(TimeSpan.frommilluses(500)).Do(x=>Console.WriteLine(“property value=“+x”).InvokeCommand(命令)
Throttle()
起作用。这是一个稳健的解决方案吗?
this.WhenAnyValue(x => x.MyProperty)
    .Delay(TimeSpan.FromMilliseconds(100))
    .Do(x => Console.WriteLine("Property value = " + x))
    .InvokeCommand(Command);
    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;
        }
    }