我正在使用MVVM,我想使用IDataErrorInfo来验证我的视图。
我当前的实现包括嵌套对象和不同的ViewModel。例如业务实体“客户”包含业务实体“地址”。我在我的视图中直接访问Address,例如“Customer.Address”。要验证地址中的更改,我必须在地址中实现IDataErrorInfo。
我在不同的Views / ViewModels中使用Customer或Address。在不同的Views / ViewModel中使用会导致不同的验证行为。因此,在实体本身中实现验证是不够的。
在ViewModel中直接显示我想要更改的属性(创建直接设置/获取实体的新属性)似乎使ViewModel方式过于僵化。而且太大了。
我不能从Base Classes继承,因为一些商业实体已经从其他对象派生(事实上我无法改变)。 我目前看到的唯一选择是向业务实体添加ViewModel接口,并将业务实体中的this []调用转发到该ViewModel接口。
是否有关于如何在ViewModel中验证这些嵌套对象的最佳实践?
编辑:另一个原因验证我没有看到Business Objects中的验证是一个有用的想法,我需要在ViewModel中使用不同的Business Objects来验证View和数据条目。 / p>
答案 0 :(得分:6)
我过去做过的一种方法是expose a ValidationDelegate on the Model,它允许ViewModel将自己的验证代码附加到模型中。
通常我这样做是因为我使用Model
图层作为普通数据对象,因此我的模型只验证基本内容,例如max-length或not-nulls,而任何不特定于数据模型的高级验证都会在ViewModel中完成。这通常包括诸如确保项目是唯一的,或者用户有权将值设置为特定范围,甚至包括仅针对特定操作进行验证的情况。
public class CustomerViewModel
{
// Keeping these generic to reduce code here, but it
// should include PropertyChange notification
public AddressModel Address { get; set; }
public CustomerViewModel()
{
Address = new AddressModel();
Address.AddValidationDelegate(ValidateAddress);
}
// Validation Delegate to validate Adderess
private string ValidateAddress(object sender, string propertyName)
{
// Do your ViewModel-specific validation here.
// sender is your AddressModel and propertyName
// is the property on the address getting validated
// For example:
if (propertyName == "Street1" && string.IsNullOrEmpty(Address.Street1))
return "Street1 cannot be empty";
return null;
}
}
以下是我通常用于验证委托的代码:
#region IDataErrorInfo & Validation Members
#region Validation Delegate
public delegate string ValidationDelegate(
object sender, string propertyName);
private List<ValidationDelegate> _validationDelegates =
new List<ValidationDelegate>();
public void AddValidationDelegate(ValidationDelegate func)
{
_validationDelegates.Add(func);
}
public void RemoveValidationDelegate(ValidationDelegate func)
{
if (_validationDelegates.Contains(func))
_validationDelegates.Remove(func);
}
#endregion // Validation Delegate
#region IDataErrorInfo for binding errors
string IDataErrorInfo.Error { get { return null; } }
string IDataErrorInfo.this[string propertyName]
{
get { return this.GetValidationError(propertyName); }
}
public string GetValidationError(string propertyName)
{
string s = null;
foreach (var func in _validationDelegates)
{
s = func(this, propertyName);
if (s != null)
return s;
}
return s;
}
#endregion // IDataErrorInfo for binding errors
#endregion // IDataErrorInfo & Validation Members
答案 1 :(得分:1)
在不同的Views / ViewModel中使用会导致不同的验证行为。
因此,您有不同的视图模型。如果您无法从某个基本视图模型继承这些视图模型,请使用aggregation:
public class Address {}
public class AddressViewModel1 : IDataErrorInfo
{
private readonly Address address;
// other stuff here
}
public class AddressViewModel2 : IDataErrorInfo
{
private readonly Address address;
// other stuff here
}
答案 2 :(得分:0)
如何使用依赖注入并将验证服务注入每个不同视图模型的客户对象?
但我认为在viewmodel中实现idataerrorinfo和所有需要的属性会更干净,但当然还有一次工作。