修改:这是此帖子原始版本的简化更新。
在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对象。
答案 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