我有一个实现 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);
}
}
试图使用它的 View
<ComboBox Name="SectionComboBox"
ItemsSource="{Binding Path=ProjectSections}"
SelectedItem="{Binding Path=SelectedPayItem.Section,
NotifyOnValidationError=True,
UpdateSourceTrigger=PropertyChanged}">
该应用程序是用 WPF 编写的,WPF 文档非常稀缺。我已经通读了 Silverlight documentation 上的 along with 其他一些 blog posts 我发现了 on the internet 并以博客作者建议的每种不同方式实现。每次结果相同时,
GetErrors()
方法永远不会被绑定(bind)引擎命中。任何人都可以看到我做错了什么吗?当我的模型设置了它的属性时,我可以单步调试调试器并最终在
OnErrorsChanged
事件处理程序中结束,并调用该事件。但是当它被调用时没有任何 react ,所以我很难过。在此先感谢您的帮助。
乔纳森
编辑
另外我想指出,过去几个月我一直在基类中使用 IDataErrorInfo ,没有任何问题。绑定(bind)工作,错误被报告给 View ,一切都很愉快。当我从 IDataErrorInfo 更改为 INotifyDataErrorInfo 时,验证似乎停止与 View 通信。
最佳答案
INotifyDataErrorInfo.HasErrors 属性在引发 ErrorsChanged 事件时必须返回 true。否则绑定(bind)引擎会忽略错误。您的 HasErrors 属性将始终返回 false。发生这种情况是因为您正在检查 ErrorMessage 类型的项目,但您的字典包含 KeyValuePair> 类型的项目。除此之外,计算所有项目的效率非常低。您应该改用 .Any() 。
顺便说一下,INotifyDataErrorInfo 的 MSDN 文档说明如下:
这完全是错误的,我花了几个小时才发现。
关于wpf - UI 未调用 INotifyDataErrorInfo.GetErrors(),我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/24518520/