更新:我通过改进我的switch语句来解决这个问题。使用名称!
我正在尝试从文本框验证一组用户输入。
我的班级设置了界面。它的片段如下:
public class PatientValidation : INotifyPropertyChanged, IDataErrorInfo
{
private string _id;
private string _fname;
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string p)
{
PropertyChangedEventHandler ph = PropertyChanged;
if (ph != null)
{
ph(this, new PropertyChangedEventArgs(p));
}
}
public string Id
{
get
{
return _id;
}
set
{
_id = value;
}
}
public string Fname
{
get
{
return _fname;
}
set
{
_fname = value;
}
}
并根据用户输入返回错误消息的switch语句:
public string this[string PropertyName]
{
get
{
string result = null;
switch (PropertyName)
{
case "Id":
if (string.IsNullOrEmpty(Id))
result = "ID number is required.";
break;
case "fname":
if (string.IsNullOrEmpty(Fname))
result = "First name is required.";
break;
}
return result;
}
}
我在XAML中的相关代码:
<Style TargetType="TextBox">
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="true">
<Setter Property="ToolTip" Value="{Binding RelativeSource={x:Static RelativeSource.Self}, Path=(Validation.Errors).CurrentItem.ErrorContent}"/>
</Trigger>
</Style.Triggers>
</Style>
<TextBox x:Name="textBox_IDNumber" Text="{Binding Id, Mode=TwoWay, ValidatesOnDataErrors=True}"/>
<TextBox x:Name="textBox_FirstName" Text="{Binding Fname, Mode=TwoWay, ValidatesOnDataErrors=True"}/>
这是我遇到的问题:只有第一个文本框(ID)被正确验证,并显示错误工具提示。没有其他文本框。 不同的绑定和触发器还没有解决问题。任何帮助将非常感激。
答案 0 :(得分:1)
错字错误(您在交换机中使用小写字母):
case "fname":
但在你的装订中:
Text="{Binding Fname
答案 1 :(得分:1)
您似乎没有在属性的设置者中调用OnPropertyChanged(nameof(FName));
或OnPropertyChanged(nameof(ID));
- 因此不会通知绑定已更新,IDataErrorInfo.<propertyName>
将会不被称为。
答案 2 :(得分:0)
您可以使用:
public class DataErrorInfoWrapper : DynamicObject, IDataErrorInfo, INotifyPropertyChanged
{
private static readonly ConcurrentDictionary<Type, Dictionary<string, PropertyInfo>> Properties = new ConcurrentDictionary<Type, Dictionary<string, PropertyInfo>>();
private readonly Dictionary<string, PropertyInfo> _typeProperties;
private readonly Func<string, string> _error;
private readonly object _target;
public string this[string columnName] => _error(columnName);
public string Error { get; }
public event PropertyChangedEventHandler PropertyChanged;
public DataErrorInfoWrapper(object target, Func<string, string> error)
{
_error = error;
_target = target;
_typeProperties = Properties.GetOrAdd(_target.GetType(), t => t.GetProperties(BindingFlags.Instance | BindingFlags.Public).Where(i => i.SetMethod != null && i.GetMethod != null).ToDictionary(i => i.Name));
}
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
result = null;
if (!_typeProperties.TryGetValue(binder.Name, out var property))
return false;
var getter = property.CreateGetter();
result = getter.DynamicInvoke(_target);
return true;
}
public override bool TrySetMember(SetMemberBinder binder, object value)
{
if (!_typeProperties.TryGetValue(binder.Name, out var property))
return false;
var setter = property.CreateSetter();
setter.DynamicInvoke(_target, value);
RaisePropertyChanged(binder.Name);
return true;
}
protected virtual bool SetProperty<TValue>(ref TValue storage, TValue value, [CallerMemberName] string propertyName = null)
{
if (EqualityComparer<TValue>.Default.Equals(storage, value))
return false;
storage = value;
RaisePropertyChanged(propertyName);
return true;
}
protected virtual bool SetProperty<TValue>(ref TValue storage, TValue value, Action onChanged, [CallerMemberName] string propertyName = null)
{
if (EqualityComparer<TValue>.Default.Equals(storage, value))
return false;
storage = value;
onChanged?.Invoke();
RaisePropertyChanged(propertyName);
return true;
}
protected void RaisePropertyChanged([CallerMemberName] string propertyName = null)
{
OnPropertyChanged(propertyName);
}
protected virtual void OnPropertyChanged(PropertyChangedEventArgs args)
{
PropertyChanged?.Invoke(this, args);
}
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
OnPropertyChanged(new PropertyChangedEventArgs(propertyName));
}
}
和扩展方法:
public static class TypeExtensions
{
private static readonly ConcurrentDictionary<PropertyInfo, Delegate> Getters = new ConcurrentDictionary<PropertyInfo, Delegate>();
private static readonly ConcurrentDictionary<PropertyInfo, Delegate> Setters = new ConcurrentDictionary<PropertyInfo, Delegate>();
public static Delegate CreateGetter(this PropertyInfo property)
{
return Getters.GetOrAdd(property, p =>
{
var parameter = Expression.Parameter(p.DeclaringType, "o");
var delegateType = typeof(Func<,>).MakeGenericType(p.DeclaringType, p.PropertyType);
var lambda = Expression.Lambda(delegateType, Expression.Property(parameter, p.Name), parameter);
return lambda.Compile();
});
}
public static Delegate CreateSetter(this PropertyInfo property)
{
return Setters.GetOrAdd(property, p =>
{
var parameter = Expression.Parameter(p.DeclaringType, "o");
var valueParm = Expression.Parameter(p.PropertyType, "value");
var delegateType = typeof(Action<,>).MakeGenericType(p.DeclaringType, p.PropertyType);
var lambda = Expression.Lambda(delegateType, Expression.Assign(Expression.Property(parameter, p.Name), valueParm), parameter, valueParm);
return lambda.Compile();
});
}
}