我有一个模型同时实现INotifyPropertyChanged
和INotifyDataErrorInfo
的模型。当我修改了属性时,Property changed 事件就会触发,但由于某种原因,当我引发 Error 事件处理程序时,UI 确实会调用 GetErrors 方法。这会导致验证错误不会呈现到 UI。
有人可以看看我是如何设置 INotifyDataErrorInfo 并告诉我是否做错了什么吗?
基本模型实现
public class BaseChangeNotify : INotifyPropertyChanged, INotifyDataErrorInfo
{
private bool isDirty;
private Dictionary<string, List<string>> errors = new Dictionary<string, List<string>>();
public BaseChangeNotify()
{
}
public event PropertyChangedEventHandler PropertyChanged;
public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;
public bool IsDirty
{
get
{
return this.isDirty;
}
set
{
this.isDirty = value;
this.OnPropertyChanged();
}
}
public bool HasErrors
{
get
{
return this.errors.Count(e => e.GetType() == typeof(ErrorMessage)) > 0;
}
}
public IEnumerable GetErrors(string propertyName)
{
if (string.IsNullOrEmpty(propertyName) ||
!this.errors.ContainsKey(propertyName))
{
return null;
}
return this.errors[propertyName];/*.Where(e => (e is ErrorMessage));*/
}
protected virtual void AddError(string propertyName, string error, bool isWarning = false)
{
if (!this.errors.ContainsKey(propertyName))
{
this.errors[propertyName] = new List<string>();
}
if (!this.errors[propertyName].Contains(error))
{
if (isWarning)
{
this.errors[propertyName].Add(error);
}
else
{
this.errors[propertyName].Insert(0, error);
}
this.OnErrorsChanged(propertyName);
}
}
protected virtual void RemoveError(string propertyName, string error)
{
if (this.errors.ContainsKey(propertyName) &&
this.errors[propertyName].Contains(error))
{
this.errors[propertyName].Remove(error);
if (this.errors[propertyName].Count == 0)
{
this.errors.Remove(propertyName);
}
this.OnErrorsChanged(propertyName);
}
}
public virtual void OnPropertyChanged([CallerMemberName] string propertyName = "")
{
// Perform the IsDirty check so we don't get stuck in a infinite loop.
if (propertyName != "IsDirty")
{
this.IsDirty = true; // Each time a property value is changed, we set the dirty bool.
}
if (this.PropertyChanged != null)
{
// Invoke the event handlers attached by other objects.
try
{
// When unit testing, this will always be null.
if (Application.Current != null)
{
try
{
Application.Current.Dispatcher.Invoke(() =>
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName)));
}
catch (Exception)
{
throw;
}
}
else
{
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
catch (Exception)
{
throw;
}
}
}
/// <summary>
/// Called when an error has changed for this instance.
/// </summary>
/// <param name="propertyName">Name of the property.</param>
public virtual void OnErrorsChanged([CallerMemberName] string propertyName = "")
{
if (string.IsNullOrWhiteSpace(propertyName))
{
return;
}
if (this.ErrorsChanged != null)
{
this.ErrorsChanged(this, new DataErrorsChangedEventArgs(propertyName));
}
}
}
使用实现的模型
public class PayItem : BaseChangeNotify
{
private Section section;
public Section Section
{
get
{
return this.section;
}
set
{
this.section = value;
this.ValidateSection();
this.OnPropertyChanged();
}
}
private void ValidateSection([CallerMemberName] string propertyName = "")
{
const string sectionError = "You must select a Section.";
if (this.Section == null || this.Section.Name.Length > 1)
{
this.AddError(propertyName, sectionError);
}
else
{
this.RemoveError(propertyName, sectionError);
}
}
视图试图使用它
<ComboBox Name="SectionComboBox"
ItemsSource="{Binding Path=ProjectSections}"
SelectedItem="{Binding Path=SelectedPayItem.Section,
NotifyOnValidationError=True,
UpdateSourceTrigger=PropertyChanged}">
该应用程序是用 WPF 编写的,而 WPF 文档非常稀缺。我已经阅读了有关它的Silverlight 文档以及我在 Internet 上找到的其他一些博客文章,并以博客作者建议的每种不同方式实施。每次结果都相同时,该方法永远不会被 Binding 引擎命中。GetErrors()
谁能看到我做错了什么?当我的模型设置了它的属性时,我可以单步调试调试器并最终在OnErrorsChanged
事件处理程序中结束,并且事件被调用。但是,当它被调用时什么都没有发生,所以我很难过。
提前感谢您的帮助。
乔纳森
编辑
另外我想指出,过去几个月我一直在基类中使用 IDataErrorInfo ,没有任何问题。绑定工作,错误报告给视图,一切都很开心。当我从 IDataErrorInfo 更改为 INotifyDataErrorInfo 时,验证似乎停止与视图通信。