请提供更详细的解决方案!我使用的代码几乎与Karel所示的代码相同: Using dataAnnonation regular expression validation attribute in Wpf Mvvm IdataErrorInfo
它就像一个魅力! 我有一个要在其中使用Attributes和IDataErrorInfo进行验证的模型,该模型可以完美地工作。
simplified Model:
public class SiESTAModel : BaseModel
{
[Required]
public string MyTestsceanrioNameTemp { get; set; }
}
在我的BaseModel类中,我有运行以下代码:
public class BaseModel : INotifyPropertyChanged, IDataErrorInfo
{
private static List<PropertyInfo> _propertyInfos;
public Dictionary<string, string> Errors { get; set; } = new Dictionary<string, string>();
public string this[string columnName]
{
get
{
CollectErrors();
return Errors.ContainsKey(columnName) ? Errors[columnName] : string.Empty;
}
}
private void CollectErrors()
{
Errors.Clear();
PropertyInfos.ForEach(
prop =>
{
//Validate generically
var errors = new List<string>();
var isValid = TryValidateProperty(prop, errors);
if (!isValid)
Errors.Add(prop.Name, errors.First());
});
// we have to this because the Dictionary does not implement INotifyPropertyChanged
OnPropertyChanged(nameof(HasErrors));
OnPropertyChanged(nameof(IsOk));
// commands do not recognize property changes automatically
OnErrorsCollected();
}
private List<PropertyInfo> PropertyInfos
{
get
{
return _propertyInfos
?? (_propertyInfos =
GetType()
.GetProperties(BindingFlags.Public | BindingFlags.Instance)////////////////////////////////////////////
.Where(prop => prop.IsDefined(typeof(ValidationAttribute), true))
.ToList());
}
}
private bool TryValidateProperty(PropertyInfo propertyInfo, List<string> propertyErrors)
{
var results = new List<ValidationResult>();
var context = new ValidationContext(this) { MemberName = propertyInfo.Name };
var propertyValue = propertyInfo?.GetValue(this);
// Validate the property
var isValid = Validator.TryValidateProperty(propertyValue, context, results);
if (results.Any())
{
propertyErrors.AddRange(results.Select(c => c.ErrorMessage));
}
return isValid;
}
}
此模型是在我的ViewModel中创建的:
public class DataErrorInfoViewModel : BaseViewModel
{
public SiESTAModel SiESTA { get; set; }
public DataErrorInfoViewModel()
{
// create SiESTA
SiESTA = new SiESTAModel();
}
}
在MainView中,我有一些文本框用于实现登录并检查输入值。此登录是作为用户控件在视图中实现的,非常适合MainView中的所有属性。
例如:
TextBox Text="{Binding CurrentUser.SiestaIp, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay, ValidatesOnDataErrors=True}" MinWidth="180" Width="AUTO" Margin="10,0,10,0"
但是现在我想通过新窗口添加一些新设备,并且我还要在此窗口中检查输入值。我已经用MVVM light和Messenger来实现了。
ViewModel:
public RelayCommand OpenAddWindowCommand { get; private set; }
OpenAddWindowCommand= new RelayCommand(() =>
{
MessengerInstance.Send(new OpenAddWindowMessage());
});
消息:
public class OpenAddWindowMessage
{
public OpenAddWindowMessage()
{
}
}
在我的视图项目中,我实现了这样的消息侦听器类,该类通过绑定来调用。
public class MessageListener
{
public AddWindow TempAddWindow;
public MessageListener()
{
InitMessenger();
}
private void InitMessenger()
{
Messenger.Default.Register<OpenAddWindowMessage>(this, msg =>
{
TempAddWindow = new AddWindow();
TempAddWindow.ShowDialog();
}
);
}
}
在这个AddWindow视图中,我有一些文本框,应该检查这些文本框是否需要在文章开头看到。数据上下文也是我的MainViewModel,就像在MainView中一样。
<TextBox FontSize="16" Text="{Binding SiESTA.MyTestsceanrioNameTemp, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay, ValidatesOnDataErrors=true}" Grid.Column="1" Grid.Row="0"></TextBox>
现在是问题所在!如果仅打开MainView窗口,则IdataErrorInfo可以完美工作。但是,当第二个窗口打开并获得焦点时,我的媒体资源的获取值就会从基本模型中崩溃。
崩溃行:
var propertyValue = propertyInfo.GetValue(this);
例外:
System.Reflection.TargetException->对象与目标类型不匹配。
这是因为反射不仅从新打开的AddWindow收集值,而且还从mainview窗口收集我的Loginvalues,我只想检查MainWindow是否打开。而且,主视图属性中的getvalue崩溃。
protected List<PropertyInfo> PropertyInfos
{
get
{
return _propertyInfos
?? (_propertyInfos =
GetType()
.GetProperties(BindingFlags.Public | BindingFlags.Instance)
.Where(prop => prop.IsDefined(typeof(ValidationAttribute), true))
.ToList());
}
}
那么,该怎么做才能使反射仅从实际的优化窗口中收集值?还是可以解决其他问题?谢谢!我希望这可以解释清楚:)