C# DataGridRow错误指示器不使用INotifyDataErrorInfo
我正在尝试更新ViewModel以使用INotifyDataErrorInfo而不是IDataErrorInfo,并遇到以下问题: 当前编辑字段的验证似乎工作正常,但行级错误指示器直到我结束对字段的编辑并出现错误,然后开始重新编辑它时才会出现。之后,错误指示器消失,事件修复后验证错误 换句话说: 第一次编辑行时,文本框轮廓正确地变为红色,但行指示器没有出现。重新编辑行会导致显示行指示符。修复验证错误会导致字段轮廓消失,但留下感叹号 请注意,IDataErrorInfo似乎工作正常。我遇到麻烦的是INotifyDataErrorInfo 解决方案的一半:将绑定更改为双向会使行指示符正确显示,但它仍然不想消失 以下是观点:C# DataGridRow错误指示器不使用INotifyDataErrorInfo,c#,.net,wpf,.net-4.5,inotifydataerrorinfo,C#,.net,Wpf,.net 4.5,Inotifydataerrorinfo,我正在尝试更新ViewModel以使用INotifyDataErrorInfo而不是IDataErrorInfo,并遇到以下问题: 当前编辑字段的验证似乎工作正常,但行级错误指示器直到我结束对字段的编辑并出现错误,然后开始重新编辑它时才会出现。之后,错误指示器消失,事件修复后验证错误 换句话说: 第一次编辑行时,文本框轮廓正确地变为红色,但行指示器没有出现。重新编辑行会导致显示行指示符。修复验证错误会导致字段轮廓消失,但留下感叹号 请注意,IDataErrorInfo似乎工作正常。我遇到麻烦的是
<DataGrid ItemsSource="{Binding Items, ValidatesOnNotifyDataErrors=True}" AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTextColumn Header="Name" Binding="{Binding Name, ValidatesOnNotifyDataErrors=True,Mode=TwoWay}" />
</DataGrid.Columns>
</DataGrid>
下面是视图模型:
public class Item : INotifyDataErrorInfo, INotifyPropertyChanged
{
Dictionary<string, IEnumerable<string>> _errors = new Dictionary<string,IEnumerable<string>>();
string _name;
public string Name
{
get { return _name; }
set
{
if (_name != value)
{
ValidateProperty("Name", value);
_name = value;
RaisePropertyChanged("Name");
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged(string p)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(p));
}
private void ValidateProperty(string p, object value)
{
if (p == "Name")
{
if (string.IsNullOrWhiteSpace((string)value))
_errors["Name"] = new[] { "Name is required." };
else
_errors["Name"] = new string[0];
}
if (ErrorsChanged != null)
ErrorsChanged(this, new DataErrorsChangedEventArgs(null));
}
public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;
public System.Collections.IEnumerable GetErrors(string propertyName)
{
if (string.IsNullOrEmpty(propertyName))
return _errors.Values.SelectMany(es2 => es2);
IEnumerable<string> es;
_errors.TryGetValue(propertyName ?? "", out es);
return es;
}
public bool HasErrors
{
get
{
var e = _errors.Values.Any(es => es.Any());
return e;
}
}
}
公共类项:INotifyDataErrorInfo,INotifyPropertyChanged
{
字典_errors=新字典();
字符串\u名称;
公共字符串名
{
获取{return\u name;}
设置
{
如果(_name!=值)
{
ValidateProperty(“名称”,值);
_名称=值;
RaiseProperty变更(“名称”);
}
}
}
公共事件属性更改事件处理程序属性更改;
私有void raiseProperty已更改(字符串p)
{
if(PropertyChanged!=null)
房地产变更(这是新的房地产变更发展(p));
}
私有void ValidateProperty(字符串p,对象值)
{
如果(p==“名称”)
{
if(string.IsNullOrWhiteSpace((string)值))
_错误[“名称”]=新[]{“名称是必需的。”};
其他的
_错误[“名称”]=新字符串[0];
}
if(ErrorsChanged!=null)
ErrorsChanged(这是新数据ErrorSchangedEventArgs(null));
}
公共事件事件处理程序错误更改;
public System.Collections.IEnumerable GetErrors(字符串propertyName)
{
if(string.IsNullOrEmpty(propertyName))
返回_errors.Values.SelectMany(es2=>es2);
可数名词;
_错误。TryGetValue(propertyName??,输出es);
返回es;
}
公共布尔错误
{
得到
{
var e=_errors.Values.Any(es=>es.Any());
返回e;
}
}
}
似乎这个问题已经被问过了,但被原作者删除了:
原始问题的副本,但此处没有答案:
编辑:
以下是我的测试源代码:
以下是我提交给MS的报告:
我知道我以前告诉过您将绑定模式设置为双向,这是正确的,不过您还必须小心如何定义验证规则。如果你介意在这两者之间找到平衡,一切都会很好 这里有一个例子,一切都很好。正如我提到的,我不能认同你的例子,我遗漏了一些细节,以便能够重现你的问题,因此这里是一个简短的例子
<Grid>
<DataGrid
CanUserAddRows="True"
AutoGenerateColumns="False"
ItemsSource="{Binding Pricelist}" >
<DataGrid.Columns>
<DataGridTextColumn
Header="Price"
Width="60"
Binding="{Binding Price,
Mode=TwoWay,
UpdateSourceTrigger=PropertyChanged,
ValidatesOnDataErrors=True}">
</DataGridTextColumn>
</DataGrid.Columns>
</DataGrid>
</Grid>
这是实现INotifyDataErrorInfo的类
public class Owner : INotifyPropertyChanged, INotifyDataErrorInfo
{
public Owner()
{
FailedRules = new Dictionary<string, string>();
}
private Dictionary<string, string> FailedRules
{
get;
set;
}
public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;
public IEnumerable GetErrors(string propertyName)
{
if (FailedRules.ContainsKey(propertyName))
return FailedRules[propertyName];
else
return FailedRules.Values;
}
internal void FireValidation()
{
if (lastName.Length > 20)
{
if (!FailedRules.ContainsKey("LastName"))
FailedRules.Add("LastName", "Last name cannot have more than 20 characters");
}
else
{
if (FailedRules.ContainsKey("LastName"))
FailedRules.Remove("LastName");
}
NotifyErrorsChanged("LastName");
}
public bool HasErrors
{
get { return FailedRules.Count > 0; }
}
private void NotifyErrorsChanged(string propertyName)
{
if (ErrorsChanged != null)
ErrorsChanged(this, new DataErrorsChangedEventArgs(propertyName));
}
}
公共类所有者:INotifyPropertyChanged,INotifyDataErrorInfo
{
公共所有者()
{
FailedRules=新字典();
}
专用字典故障规则
{
得到;
设置
}
公共事件事件处理程序错误更改;
公共IEnumerable GetErrors(字符串propertyName)
{
if(FailedRules.ContainsKey(propertyName))
返回失败的规则[propertyName];
其他的
返回FailedRules.值;
}
内部无效验证()
{
如果(lastName.Length>20)
{
如果(!FailedRules.ContainsKey(“LastName”))
FailedRules.Add(“姓氏”,“姓氏不能超过20个字符”);
}
其他的
{
if(FailedRules.ContainsKey(“姓氏”))
失败规则。删除(“姓氏”);
}
NOTIFYERRSCHANGED(“姓氏”);
}
公共布尔错误
{
获取{return FailedRules.Count>0;}
}
私有void NOTIFYERRSCHANGED(字符串属性名称)
{
if(ErrorsChanged!=null)
ErrorsChanged(这是新数据ErrorSchangedEventArgs(propertyName));
}
}
我知道我以前告诉过您将绑定模式设置为双向,这是正确的,不过您还必须小心如何定义验证规则。如果你介意在这两者之间找到平衡,一切都会很好
这里有一个例子,一切都很好。正如我提到的,我不能认同你的例子,我遗漏了一些细节,以便能够重现你的问题,因此这里是一个简短的例子
<Grid>
<DataGrid
CanUserAddRows="True"
AutoGenerateColumns="False"
ItemsSource="{Binding Pricelist}" >
<DataGrid.Columns>
<DataGridTextColumn
Header="Price"
Width="60"
Binding="{Binding Price,
Mode=TwoWay,
UpdateSourceTrigger=PropertyChanged,
ValidatesOnDataErrors=True}">
</DataGridTextColumn>
</DataGrid.Columns>
</DataGrid>
</Grid>
这是实现INotifyDataErrorInfo的类
public class Owner : INotifyPropertyChanged, INotifyDataErrorInfo
{
public Owner()
{
FailedRules = new Dictionary<string, string>();
}
private Dictionary<string, string> FailedRules
{
get;
set;
}
public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;
public IEnumerable GetErrors(string propertyName)
{
if (FailedRules.ContainsKey(propertyName))
return FailedRules[propertyName];
else
return FailedRules.Values;
}
internal void FireValidation()
{
if (lastName.Length > 20)
{
if (!FailedRules.ContainsKey("LastName"))
FailedRules.Add("LastName", "Last name cannot have more than 20 characters");
}
else
{
if (FailedRules.ContainsKey("LastName"))
FailedRules.Remove("LastName");
}
NotifyErrorsChanged("LastName");
}
public bool HasErrors
{
get { return FailedRules.Count > 0; }
}
private void NotifyErrorsChanged(string propertyName)
{
if (ErrorsChanged != null)
ErrorsChanged(this, new DataErrorsChangedEventArgs(propertyName));
}
}
公共类所有者:INotifyPropertyChanged,INotifyDataErrorInfo
{
公共所有者()
{
FailedRules=新字典();
}
专用字典故障规则
{
得到;
设置
}
公共事件事件处理程序错误更改;
公共IEnumerable GetErrors(字符串propertyName)
{
if(FailedRules.ContainsKey(propertyName))
返回失败的规则[propertyName];
其他的
返回FailedRules.值;
}
内部无效验证()
{
如果(lastName.Length>20)
{
如果(!FailedRules.ContainsKey(“LastName”))
FailedRules.Add(“姓氏”,“姓氏不能超过20个字符”);
}
其他的
{
if(FailedRules.ContainsKey(“姓氏”))
失败规则。删除(“姓氏”);
}
NOTIFYERRSCHANGED(“姓氏”);
}
公共布尔错误
{
得到
public class Owner : INotifyPropertyChanged, INotifyDataErrorInfo
{
public Owner()
{
FailedRules = new Dictionary<string, string>();
}
private Dictionary<string, string> FailedRules
{
get;
set;
}
public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;
public IEnumerable GetErrors(string propertyName)
{
if (FailedRules.ContainsKey(propertyName))
return FailedRules[propertyName];
else
return FailedRules.Values;
}
internal void FireValidation()
{
if (lastName.Length > 20)
{
if (!FailedRules.ContainsKey("LastName"))
FailedRules.Add("LastName", "Last name cannot have more than 20 characters");
}
else
{
if (FailedRules.ContainsKey("LastName"))
FailedRules.Remove("LastName");
}
NotifyErrorsChanged("LastName");
}
public bool HasErrors
{
get { return FailedRules.Count > 0; }
}
private void NotifyErrorsChanged(string propertyName)
{
if (ErrorsChanged != null)
ErrorsChanged(this, new DataErrorsChangedEventArgs(propertyName));
}
}