0

编辑:这是这篇文章原始版本的简化更新。

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

<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:根据伦理逻辑的回答,我重构了我的代码。NumericTextBox现在使用一个底层视图模型类,该类提供一个依赖属性,该值绑定到由NumericTextBox声明的TextBox的Text属性。此外, NumericTextBox使用视图模型作为其数据上下文。viewmodel 现在负责检查 Value 属性的变化。由于NumericTextBox的值限制是可定制的(例如可以调整最小值),它会将这些设置转发给 viewmodel 对象。

4

2 回答 2

0

这样做而不是创建任何 Dependency Property 。验证应用于 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}"/>

我希望这将有所帮助。

于 2012-07-25T13:48:34.313 回答
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

于 2012-07-26T13:11:41.440 回答