我已经看到了两种在.Net 4.0中进行数据验证的方法。目前我使用像这样的IDataErrorInfo,但这里的问题是"这个"只有在调用Age属性的getter时才调用IDataErrorInfo。我在setter中有一些逻辑,它依赖于Age的有效值。
public int Age
{
get { return _age; }
set
{
_age = value;
OnPropertyChanged("Age");
//My methods to call when Age is valid
}
}
public string this[string columnName]
{
get
{
string error = null;
switch (columnName)
{
case "Age":
if (Age < 10 || Age > 100)
error="The age must be between 10 and 100";
break;
}
return error;
}
}
我无法调用这些方法,因为调用setter时没有进行验证,只有在调用getter时才会进行验证。有人可以帮助我理解为什么它的设计就像那样。在我看来,验证应该接近setter其中赋值。
我必须使用异常验证
将我的实现更改为此public int Age
{
get { return _age; }
set
{
if (value < 10 || value > 100)
throw new ArgumentException("The age must be between 10 and 100");
_age = value;
//My methods to call when Age is valid
}
}
我问这个问题,因为现有的实现基于我项目中的IDataErrorInfo,并且有很多属性得到验证。有一些解决方案可以让我保持IDataerrorInfo实现并实现与实现异常验证相同的效果。
我不想在我的属性设置器上抛出异常,因为它是microsoft的设计指南
如果可能,请不要将异常用于正常的控制流程。除了 对于系统故障和具有潜在竞争条件的操作, 框架设计者应该设计API,以便用户可以编写代码 这不会引发异常。例如,您可以提供一种方法 在调用成员之前检查前提条件,以便用户可以编写 不抛出异常的代码。
并且我也不想抛出我在视图模型代码中没有捕获的异常。
这是我的xaml
<TextBox Text="{Binding Age, ValidatesOnDataErrors=True,
NotifyOnValidationError=True, ValidatesOnExceptions=True,
UpdateSourceTrigger=PropertyChanged}"/>
答案 0 :(得分:2)
绑定首先设置值,然后调用getter aaand然后调用indexer进行验证。但是,您的问题是您希望索引器首先出现。这不是wpf的工作原理。
基本上,wpf在使用IDataErrorInfo时为您提供了所有自由,因此您必须自己实现所有。让我给你举个例子:
public int Age
{
get { return _age; }
set
{
int oldVal = _age;
_age = value;
if(Validate("Age") == null)
{
// Do whatever you want
OnPropertyChanged("Age");
}
else
{
// You can rollback value or not, it wouldnt matter...
// PropertyChanged will not be fired!!!
_age = oldVal;
}
}
}
public string this[string columnName]
{
get
{
return Validate(columnName);
}
}
public string Validate(string propertyName)
{
string error = null;
switch (propertyName)
{
case "Age":
if (_age< 10 || _age > 100)
error = "The age must be between 10 and 100";
}
return error;
}
答案 1 :(得分:0)
在我看来,实现这一目标的最佳方法是在setter中调用check方法,如果验证结果为false,则不要将value设置为property并设置一些“InvalidState”标志。否则设置值并继续。
使用InvalidState标志,当调用任何取决于对象状态的方法时,可以抛出InvalidOperationException。
您可以使用基本的布尔值InvalidState,或者您可以将枚举用于不同的状态( NotInitialized ,有效,无效等)来管理代码流。
答案 2 :(得分:0)
这里的问题是由于你的设计而不是在.NET或WPF中完成的任何事情。
根据它的声音,您会立即根据代码中的OnPropertyChanged()
调用更新内容。在使用涉及用户的UI绑定元素时,我不会这样做,因为人类是任何系统中的弱点,并且您总是会在某个时刻从用户那里获得无效输入。
您应该通过保存命令而不是基于OnPropertyChanged()
的持续更新来执行确定性更新。表单验证的要点是,在将数据提交到底层结构之前,您可以确定性地验证整个数据集。
您应该执行类似添加私有Boolean
变量以存储Age
属性的验证状态并通过Command
方法启用/禁用保存ICommand.CanExecute()
的操作