我正在使用RIA服务和LinqToEntitiesDomainService<>和Silverlight 5 Beta在客户端生成DomainContext代码。我在我的模型/实体中有数据注释来进行基本验证,当直接使用模型时,DataForm等控件可以开箱即用地执行验证。但我将我的模型包装在ViewModel中,所以我失去了所有的自动验证。这是一个简化的例子:
// In DataModel assembly, regenerated on the client side by RIA Services
public class PetModel
{
[Required]
public string Name { get; set; }
}
// Only on the client side
public class PetViewmodel
{
private PetModel _model;
public PetViewmodel(PetModel model)
{
_model = model;
}
public string Name
{
get { return _model.Name; }
set { _model.Name = value; }
}
}
我的问题是:如何确保Name
在客户端被视为Required
而不重复ViewModel中的所有注释? (我将来可能不得不将这些实体与不同的ViewModel一起使用 - 我希望保留相同的注释)
我想到手动将MetadataType
属性添加到ViewModel,指向模型类型:
[MetadataType(typeof(PetModel))]
public class PetViewmodel
{
...
}
但是,MetadataTypeAttribute
的Silverlight 5版本中没有System.ComponentModel.DataAnnotations
。
编辑:澄清 - 我的实体的元数据包含在具有嵌套类的实体中。我手动编写此类,因为我的L2E模型位于单独的程序集中,因此DomainService向导不会为我生成它。
[MetadataType(typeof(Metadata))]
public partial class PetModel
{
[Required]
public string Name { get; set; }
public class Metadata
{
[Required]
public string Name { get; set; }
}
}
如果我理解正确,这应该是向导生成元数据的方式。 RIA服务代码生成器在客户端代码中生成正确的数据注释,因此它可以正确地提取它。
答案 0 :(得分:1)
我找到了一种方法来做到这一点。希望它能在将来帮助某人:
我为执行验证的viewmodel使用了一个基类。在该基类上,我实现了INotifyDataErrorInfo
,并且我覆盖了NotifyOfPropertyChange
方法(这是Caliburn.Micro的一部分,但如果您不使用,则可以轻松地附加到PropertyChanged
1}}模型的事件)。在事件处理程序中,我对该属性执行验证。在验证代码中,我使用反射来查找相同名称的属性,以及属性上的任何验证属性(RequiredAttribute
,RangeAttribute
等)。然后,我使用这些属性中的值来验证已更改属性的新值,创建ValidationResult
个对象并将其添加到List<ValidationResult>
。如果所有“本地”验证都通过,那么我继续执行“远程”验证(即需要与服务器交互的验证,例如检查唯一性)。
这是很多工作,但不幸的是,这或类似的东西是必要的。所有MS示例似乎都不使用MVVM。我认为这只是为了让它们简短/简单,但在设计对象模型时,MS的Silverlight团队似乎没有认真考虑MVVM。