基于IDataErrorInfo的验证无效

时间:2012-07-25 11:47:48

标签: c# wpf validation xaml idataerrorinfo

修改:这是此帖子原始版本的简化更新。

在WPF中,我实现了一个 UserControl (称为“NumericTextBox”),它使用* DependencyProperty'Value',与 Text 属性保持同步> TextBox (xaml):

<TextBox.Text>
  <Binding Path="Value" 
           Mode="TwoWay"
           ValidatesOnDataErrors="True"
           NotifyOnValidationError="True"
           UpdateSourceTrigger="PropertyChanged" />
</TextBox.Text>

出于验证目的,我使用 IDataErrorInfo 接口(xaml.cs):

public partial class NumericTextbox : Textbox, IDataErrorInfo {
    public double Value {
        get { return (double)GetValue(ValueProperty); }
        set { SetValue(ValueProperty, value); }
    }

    public static readonly DependencyProperty ValueProperty =
        DependencyProperty.Register("Value", typeof(double),  
                                    typeof(NumericTextBox), 
                                    new PropertyMetadata(default(double)));

    public string this[string columnName]
    {
        // Never gets called!
        get { /* Some validation rules here */ }
    }
}

如源代码所述,get属性永远不会被调用,因此无验证。你看到问题的原因吗?

Edit2 :根据ethicallogics的回答,我重新构建了我的代码。 NumericTextBox 现在使用基础viewmodel类,该类提供绑定到 TextBox的 Text 属性的依赖属性 Value NumericTextBox 声明。另外, NumericTextBox 使用viewmodel作为其datacontext。 viewmodel现在负责检查Value属性的更改。由于 NumericTextBox 的值限制是可自定义的(例如,可以调整最小值),因此它会将这些设置转发给viewmodel对象。

2 个答案:

答案 0 :(得分:0)

这样做而不是创建任何依赖属性。验证在ViewModel中应用,而不是在Control或View中。试试这样,我希望这会有所帮助。

public class MyViewModel : INotifyPropertyChanged, IDataErrorInfo
{
    public MyViewModel()
    {
        Value = 30;
    }
    private double _value;

    [Range(1, 80, ErrorMessage = "out of range")]
    public double Value
    {
        get
        {
            return _value;
        }
        set
        {
            _value = value;
            ValidationMessageSetter("Value", value);
        }
    }

    private void ValidationMessageSetter(string propertyName, object value)
    {
        Notify(propertyName);
        string validationresult = ValidateProperty(propertyName, value);
        if (!string.IsNullOrEmpty(validationresult) && !_dataErrors.ContainsKey(propertyName))
            _dataErrors.Add(propertyName, validationresult);
        else if (_dataErrors.ContainsKey(propertyName))
                _dataErrors.Remove(propertyName);

    }

    #region INotifyPropertyChanged Members

    public event PropertyChangedEventHandler PropertyChanged;

    #endregion

    private void Notify(string str)
    { 
        if(PropertyChanged!=null)
            PropertyChanged(this,new PropertyChangedEventArgs(str));
    }

    private string ValidateProperty(string propertyName,object value)
    {
        var results = new List<ValidationResult>(2);
        string error = string.Empty;

        bool result = Validator.TryValidateProperty(
            value,
            new ValidationContext(this, null, null)
            {
                MemberName = propertyName
            },
            results);

        if (!result && (value == null || ((value is int || value is long) && (int)value == 0) || (value is decimal && (decimal)value == 0)))
            return null;

        if (!result)
        {
            ValidationResult validationResult = results.First();
            error = validationResult.ErrorMessage;
        }

        return error;    
    }

    #region IDataErrorInfo Members

    private Dictionary<string, string> _dataErrors = new Dictionary<string, string>();

    public string Error
    {
        get { throw new NotImplementedException(); }
    }

    public string this[string columnName]
    {
        get
        {
            if (_dataErrors.ContainsKey(columnName))
                return _dataErrors[columnName];
            else
                return null;
        }
    }

    #endregion
}

<TextBox Text="{Binding Value, Mode=TwoWay, ValidatesOnDataErrors=True, UpdateSourceTrigger=PropertyChanged}"/>

我希望这会有所帮助。

答案 1 :(得分:0)

IDataErrorInfo接口应该在绑定的对象上实现,而不是在具有DependencyProperty的对象上实现。

在您的示例中,如果您想使用此机制进行验证,那么您的视图模型需要对Value属性执行以下操作:

public class ViewModel : IDataErrorInfo
{
    public string this[string columnName]
    {
        // Never gets called!
        get
        { 
            if (columnName == "Value")
                return GetValidationMessageForValueField();

            return null;
        }
    }
}

我猜你真正想要做的就是验证有人在TextBox中输入非数字值?如果是这种情况,您可能希望采用与使用IDataErrorInfo

不同的方法