Wpf 通过比较一个实体与另一个实体的属性进行验证

Wpf 通过比较一个实体与另一个实体的属性进行验证,wpf,validation,Wpf,Validation,以下是我所拥有的: 在视图中有一个选项卡控件,它有两个选项卡(sys1和sys2),每个选项卡都有相同的文本框,这些文本框绑定到各自实体的属性: 系统1: 系统2: 使用某种形式的验证,我希望比较这两个值,如果值不匹配,则显示一个错误(红色边框很好) 我以前使用过IDataErrorInfo,但我不确定这种类型的验证是否可行 注意:直接绑定到实体是否“正确”是另一个地点和时间的讨论。只需知道这是一个团队项目,我们的团队标准将绑定到实体,因此除非我有充分的理由,否则我无法更改。如果直接绑定

以下是我所拥有的:

在视图中有一个选项卡控件,它有两个选项卡(sys1和sys2),每个选项卡都有相同的文本框,这些文本框绑定到各自实体的属性:

系统1:


系统2:


使用某种形式的验证,我希望比较这两个值,如果值不匹配,则显示一个错误(红色边框很好)

我以前使用过IDataErrorInfo,但我不确定这种类型的验证是否可行

注意:直接绑定到实体是否“正确”是另一个地点和时间的讨论。只需知道这是一个团队项目,我们的团队标准将绑定到实体,因此除非我有充分的理由,否则我无法更改。如果直接绑定到实体时无法进行验证,那么我可能有足够的理由对此进行更改


谢谢

我通常从我的模型中公开一个验证委托,我的ViewModel可以使用它将业务规则验证附加到模型中

例如,包含对象的ViewModel可能如下所示:

public ParentViewModel()
{
    sys1.AddValidationErrorDelegate(ValidateSerial);
    sys2.AddValidationErrorDelegate(ValidateSerial);
}

private string ValidateSerial(object sender, string propertyName)
{
    if (propertyName == "Serial")
    {
        if (sys1.Serial == sys2.Serial)
            return "Serial already assigned";
    }
    return null;
}
#region IDataErrorInfo & Validation Members

/// <summary>
/// List of Property Names that should be validated
/// </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)
{
    // If user specified properties to validate, check to see if this one exists in the list
    if (ValidatedProperties.IndexOf(propertyName) < 0)
    {
        //Debug.Fail("Unexpected property being validated on " + this.GetType().ToString() + ": " + propertyName);
        return null;
    }

    string s = null;

    // If user specified a Validation method to use, Validate property
    if (_validationDelegates.Count > 0)
    {
        foreach (ValidationErrorDelegate 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
中进行验证,这就允许这样做

my
IDataErrorInfo
Model
类上的实际实现如下所示:

public ParentViewModel()
{
    sys1.AddValidationErrorDelegate(ValidateSerial);
    sys2.AddValidationErrorDelegate(ValidateSerial);
}

private string ValidateSerial(object sender, string propertyName)
{
    if (propertyName == "Serial")
    {
        if (sys1.Serial == sys2.Serial)
            return "Serial already assigned";
    }
    return null;
}
#region IDataErrorInfo & Validation Members

/// <summary>
/// List of Property Names that should be validated
/// </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)
{
    // If user specified properties to validate, check to see if this one exists in the list
    if (ValidatedProperties.IndexOf(propertyName) < 0)
    {
        //Debug.Fail("Unexpected property being validated on " + this.GetType().ToString() + ": " + propertyName);
        return null;
    }

    string s = null;

    // If user specified a Validation method to use, Validate property
    if (_validationDelegates.Count > 0)
    {
        foreach (ValidationErrorDelegate 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
#地区IDataErrorInfo和验证成员
/// 
///应验证的属性名称列表
/// 
受保护列表ValidatedProperties=新列表();
#区域验证代表
公共委托字符串ValidationErrorDelegate(对象发送方,字符串属性名称);
私有列表_validationDelegates=新列表();
public void AddValidationErrorDelegate(ValidationErrorDelegate func)
{
_validationDelegates.Add(func);
}
#endregion//验证委托
#绑定错误的区域IDataErrorInfo
字符串IDataErrorInfo.Error{get{return null;}}
字符串IDataErrorInfo。此[string propertyName]
{
获取{返回this.GetValidationError(propertyName);}
}
公共字符串GetValidationError(字符串属性名称)
{
//如果用户指定了要验证的属性,请检查列表中是否存在此属性
if(ValidatedProperties.IndexOf(propertyName)<0)
{
//Debug.Fail(“正在“+this.GetType().ToString()+”:“+propertyName”上验证意外属性);
返回null;
}
字符串s=null;
//如果用户指定了要使用的验证方法,请验证属性
如果(_validationDelegates.Count>0)
{
foreach(ValidationErrorDelegate func in_validationDelegates)
{
s=func(这是propertyName);
如果(s!=null)
{
返回s;
}
}
}
返回s;
}
#endregion//IDataErrorInfo用于绑定错误
#区域是有效的属性
公共布尔是有效的
{
得到
{
返回(GetValidationError()==null);
}
}
公共字符串GetValidationError()
{
字符串错误=null;
if(ValidatedProperties!=null)
{
foreach(ValidatedProperties中的字符串s)
{
错误=GetValidationError(s);
if(错误!=null)
{
返回误差;
}
}
}
返回误差;
}
#endregion//IsValid属性
#endregion//IDataErrorInfo和验证成员

另外,我认为直接绑定到模型没有什么错,尤其是在较小的应用程序中。它可能不是“MVVM纯粹主义”方法,但它效率高且工作量小,因此我发现它是一个非常有效的选择。

在sys1.Serial1和sys2.Serial的集合(mutator)中,您应该能够获得其他值进行比较。

这看起来不错,但是有没有一种方法可以减少编码,因为每个系统中都有相当多的属性,唯一的验证将是比较值是否相等?@John
IDataErrorInfo
代码是泛型的,通常在我的基本模型类中使用,所以它只编写一次。您需要为每个ViewModel编辑和自定义的部分是在构造函数中为任何应该验证业务规则的类附加验证委托,并编写实际的验证委托方法。。。我要问的是,如果ViewModel中的每个属性都要执行相同的操作(检查是否相等),我是否必须为它们创建一个validate方法,或者是否有一种方法可以创建单个方法。我猜不会,因为每个属性都有自己的标识符???@John您可以对其使用单个验证方法。通常我将方法命名为
ValidateModelName
,但在本例中我使用了
ValidateSerial
,因为我不知道您的模型被调用了什么。只需使用
propertyName
上的
switch
语句检查正在验证的属性。如果有人碰巧看到此线程,我只想添加一些半相关的内容。我把我的控件放在tabcontrol中,当我切换tabs时,红色边框消失了。以下是解决方案: