Joh*_*ger 3 data-binding wpf mvvm inotifydataerrorinfo
我有一个模型实现两者INotifyPropertyChanged
和INotifyDataErrorInfo
.当我修改了属性时,属性更改了事件触发,但由于某种原因,当我引发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));
}
}
}
Run Code Online (Sandbox Code Playgroud)
模型使用实现
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);
}
}
Run Code Online (Sandbox Code Playgroud)
View试图使用它
<ComboBox Name="SectionComboBox"
ItemsSource="{Binding Path=ProjectSections}"
SelectedItem="{Binding Path=SelectedPayItem.Section,
NotifyOnValidationError=True,
UpdateSourceTrigger=PropertyChanged}">
Run Code Online (Sandbox Code Playgroud)
该应用程序正在WPF中编写,WPF文档非常稀缺.我已经通过了阅读的Silverlight文档上连同其他一些博客文章,我发现在互联网上,并在每一个不同的方式博客作者建议已经落实.每次结果相同时,该GetErrors()
方法永远不会受到绑定引擎的影响.
谁能看到我做错了什么?当我的模型具有其属性集时,我可以单步执行调试器并最终在OnErrorsChanged
事件处理程序中结束,并调用该事件.当它被调用时没有任何事情发生,所以我很难过.
在此先感谢您的帮助.
乔纳森
编辑
另外我想指出,我在过去几个月里一直在基类中使用IDataErrorInfo而没有任何问题.绑定工作,错误报告给视图,一切都很高兴.当我从IDataErrorInfo更改为INotifyDataErrorInfo时,验证似乎停止与View通信.
在引发ErrorsChanged事件时,INotifyDataErrorInfo.HasErrors属性必须返回true.否则绑定引擎会忽略错误.您的HasErrors属性将始终返回false.发生这种情况是因为您正在检查ErrorMessage类型的项目,但您的字典包含KeyValuePair类型的项目<string,List <string >>.除此之外,计算所有项目是非常无效的.你应该使用.Any()代替.
顺便说一句,INotifyDataErrorInfo的MSDN文档说明如下:
请注意,绑定引擎从不使用HasErrors属性,但您可以在自定义错误报告中使用它.
这是完全错误的,我需要花费数小时才能找到它.