1

我正在使用带有 Entity Framework 4.3 的 WPF 和 MVVM 进行项目,我想知道如何执行实现 IDataErrorInfo 接口的业务逻辑验证。

我的所有模型(POCO 类)都在实现它以执行原始验证,例如最大长度、非负数等......

但是业务逻辑验证呢,比如防止重复记录呢?

想象一下,我有一个用于材料“参考”的文本框,它必须是唯一的,定义如下:

 <TextBox Text="{Binding Material.Reference, ValidatesOnDataErrors=True, NotifyOnValidationError=true, 
                                 UpdateSourceTrigger=PropertyChanged}">

该模型将成功验证引用的长度,但如果我的视图模型的材料 observablecollection 中已经有一个材料,我应该如何从我的 ViewModel 通知用户这一事实,同时利用 IDataErrorInfo 消息?

4

1 回答 1

2

过去,我通过从我的模型中公开一个验证委托来做到这一点,我的 ViewModel 可以挂钩以进行额外的业务逻辑验证

最终结果最终看起来像这样:

public class MyViewModel
{
    // Keeping these generic to reduce code here, but they
    // should be full properties with PropertyChange notification
    public ObservableCollection<MyModel> MyCollection { get; set; }
    public MyModel SelectedModel { get; set; }

    public MyViewModel()
    {
        MyCollection = DAL.GetAllModels();

        // Add the validation delegate to each object
        foreach(var model in MyCollection)
            model.AddValidationErrorDelegate(ValidateModel);
    }

    // Validation Delegate to verify the object's name is unique
    private string ValidateObject(object sender, string propertyName)
    {
        if (propertyName == "Name")
        {
            var obj = (MyModel)sender;
            var existingCount = MyCollection.Count(p => 
                p.Name == obj.Name && p.Id != obj.Id);

            if (existingCount > 0)
                return "This name has already been taken";
        }
        return null;
    }
}

我的大多数模型都继承自一个通用基类,其中包括这个验证委托。这是该基类中的相关代码,取自我关于在 MVVM 中验证业务规则的博客文章

#region IDataErrorInfo & Validation Members

/// <summary>
/// List of Property Names that should be validated.
/// Usually populated by the Model's Constructor
/// </summary>
protected List<string> ValidatedProperties = new List<string>();

#region Validation Delegate

public delegate string ValidationErrorDelegate(
    object sender, string propertyName);

private List<ValidationErrorDelegate> _validationDelegates = new List<ValidationErrorDelegate>();

public void AddValidationErrorDelegate(
    ValidationErrorDelegate func)
{
    _validationDelegates.Add(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)
{
    // Check to see if this property has any validation
    if (ValidatedProperties.IndexOf(propertyName) >= 0)
    {
        string s = null;

        foreach (var func in _validationDelegates)
        {
            s = func(this, propertyName);
            if (s != null)
                return s;
        }
    }

    return s;
}

#endregion // IDataErrorInfo for binding errors

#region IsValid Property

public bool IsValid
{
    get
    {
        return (GetValidationError() == null);
    }
}

public string GetValidationError()
{
    string error = null;

    if (ValidatedProperties != null)
    {
        foreach (string s in ValidatedProperties)
        {
            error = GetValidationError(s);
            if (error != null)
                return error;
        }
    }

    return error;
}

#endregion // IsValid Property

#endregion // IDataErrorInfo & Validation Members

这使我可以在我的模型中保留基本数据验证,并且我的 ViewModel 也可以将他们想要的任何自定义业务逻辑验证附加到模型中。

于 2012-07-23T17:32:15.533 回答