WPF DataGrid 验证错误未清除
所以我有一个 WPF DataGrid
,它绑定到 ObservableCollection
。该集合通过 IDataErrorInfo
对其成员进行验证。如果我以某种方式编辑一个单元格,使其无效,然后在按 Enter 之前按 Tab 键离开该单元格,然后返回并使其有效,该单元格将停止显示无效,但是,“!”行首的 仍然会在那里,并且 ToolTip
将引用之前的无效值。
So I have a WPF DataGrid
, which is bound to an ObservableCollection
. The collection has validation on its members, through IDataErrorInfo
. If I edit a cell in a way so as to be invalid, and then tab away from it before hitting enter, then come back and make it valid, the cell will stop showing invalid, however, the "!" at the head of the row will still be there, and the ToolTip
will reference the previous, invalid value.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(15)
对于
DataGridTextColumns
不使用Mode=TwoWay
可以解决该问题的一个版本,但似乎该问题也可能因其他原因突然出现。(任何能够很好地解释为什么不使用
Mode=TwoWay
解决这个问题的人都可能接近解决这个问题)同样的事情刚刚发生给我一个
DataGridComboBoxColumn
所以我尝试更深入地挖掘。问题不在于
Control
中显示DataGridHeaderBorder
内的ErrorTemplate
的Binding
。它正在将其Visibility
绑定到祖先DataGridRow
的Validation.HasError
(正如它应该做的那样),并且该部分正在工作。问题在于验证错误在解决后不会从
DataGridRow
中清除。在我的问题版本中,DataGridRow
开始时有 0 个错误。当我输入无效值时,出现 1 个错误,到目前为止一切顺利。但是当我解决这个错误时,它跳到了 3 个错误,所有这些错误都是一样的。在这里,我尝试使用
DataTrigger
来解决该问题,如果Validation.Errors.Count<,则将
ValidationErrorTemplate
设置为{x:Null}
/code> 不是 1。第一次迭代时效果很好,但当我第二次清除错误后,它又回来了。错误不再是 3 个,而是 7 个!经过几次迭代后,它超过了 10。我还尝试通过在
BindingExpressions
上执行UpdateSource
和UpdateTarget
来手动清除错误,但没有骰子。Validation.ClearInvalid
也没有任何效果。浏览工具包中的源代码并没有让我得到任何结果:)所以我对此没有任何好的解决方案,但我认为无论如何我应该发布我的发现..
到目前为止我唯一的“解决方法”就是隐藏
DataGridRowHeader
中的ErrorTemplate
Not using
Mode=TwoWay
forDataGridTextColumns
solves one version of the problem, however it seems that this problem can appear out of nowhere for other reasons as well.(Anyone who has a good explanation as of why not using
Mode=TwoWay
solves this in the first place is probably close to a solution to this problem)The same thing just happened to me with a
DataGridComboBoxColumn
so I tried to dig a little deeper.The problem isn't the
Binding
in theControl
that displays theErrorTemplate
insideDataGridHeaderBorder
. It is binding itsVisibility
toValidation.HasError
for the ancestorDataGridRow
(exactly as it should be doing) and that part is working.The problem is that the validation error isn't cleared from the
DataGridRow
once it is resolved. In my version of the problem, theDataGridRow
started out with 0 errors. When I entered an invalid value it got 1 error so, so far so good. But when I resolved the error it jumped up to 3 errors, all of which were the same.Here I tried to resolve it with a
DataTrigger
that set theValidationErrorTemplate
to{x:Null}
ifValidation.Errors.Count
wasn't 1. It worked great for the first iteration but once I cleared the error for the second time it was back. It didn't have 3 errors anymore, it had 7! After a couple of more iterations it was above 10.I also tried to clear the errors manually by doing
UpdateSource
andUpdateTarget
on theBindingExpressions
but no dice.Validation.ClearInvalid
didn't have any effect either. And looking through the source code in the Toolkit didn't get me anywhere :)So I don't have any good solutions to this but I thought I should post my findings anyway..
My only "workaround" so far is to just hide the
ErrorTemplate
in theDataGridRowHeader
我找到了这个问题的根本原因。它与
BindingExpressionBase
失去对BindingGroup
的引用的方式有关,因为只有BindingExpression
负责删除其验证错误
。在这种 DataGrid 验证情况下,它有多个源,可能会丢失引用:
DataGridCell.BuildVisualTree()
为DataGridCell
重建可视化树时, 属于此单元格的BindingGroup
的所有旧BindingExpressions
都会被删除,Content
属性显式更改为新值之前, 当DataGridCell
的Content
属性已更改(通过DataGridCell.BuildVisualTree()
或其他方式),BindingExpressionBase.Detach()<为旧属性值上的所有绑定调用 /code> 方法,这还会在任何
ValidationError
有机会被BindingGroup
的引用,因为大多数对BindingExpressionBase
的引用实际上都是WeakReference
,即使上述所有情况都不会导致引用的删除,但当某些内容查找
,底层BindingExpressionBase
的 TargetElementWeakReference
有可能返回null
并且属性访问器再次调用损坏的Detach()
方法通过上述发现,现在也清楚了为什么不对
DataGridTextColumn
使用Mode=TwoWay
有时会成为一种错误。问题的解决方案。DataGridTextColumn
将变为只读,并且DataGridCell
的Content
属性因此永远不会更改。我已经为此使用附加的 DependencyProperty 编写了一个解决方法。
然后将此属性绑定到
DataGridCell
的Content
属性。I found the root cause of this problem. It has to do with the way how
BindingExpressionBase
s lose their reference to theBindingGroup
, because only theBindingExpression
is responsible to remove itsValidationErrors
.In this case of DataGrid validation, it has multiple sources where it can lose the reference:
DataGridCell
byDataGridCell.BuildVisualTree()
, all the oldBindingExpressions
of theBindingGroup
that belongs to this cell are removed, before itsContent
property is changed to the new valueContent
property for theDataGridCell
is changed (byDataGridCell.BuildVisualTree()
or other way) , theBindingExpressionBase.Detach()
method is called for all the bindings on the old property value, which also removes the reference to theBindingGroup
before anyValidationError
has a chance to be removedBindingExpressionBase
are actuallyWeakReference
s, even when all the above scenarios would not cause the remove of the reference, but when something looks up theTargetElement
ofBindingExpressionBase
, there is a chance that the underlyingWeakReference
returnsnull
and the property accessor calls again the brokenDetach()
methodWith the above findings it is now also clear why not using
Mode=TwoWay
forDataGridTextColumn
can sometimes be a solution to the problem. TheDataGridTextColumn
would become read-only and theContent
property of theDataGridCell
is therefore never changed.I've written a workaround by using an attached
DependencyProperty
for this.Then attach this property with a binding to the
Content
property ofDataGridCell
.我找到了对我有用的最佳答案。只需清除
DataGrid
的RowValidationErrorTemplate
即可。在代码中
在 Xaml 中
然后制作您自己的行验证错误模板。
如果您的数据项是INotifyPropertyChanged
然后
按照您喜欢的方式编写您自己的 IsValid 方法
I found best answer that worked for me. Just clear your
DataGrid
'sRowValidationErrorTemplate
.In Code
In Xaml
Then make your own Row Validation Error Template.
If your data item is INotifyPropertyChanged
then
Write your own IsValid method, the way you like
我也有同样的问题,RowHeader 错误模板没有消失。我正在使用 INotifyDataErrorInfo。根据 Fredrik Hedblad 的研究,我提出了一个解决方法;我已修改 DataGridRowHeader 模板以使用 MultiBinding 来实现 ValidationErrorTemplate 可见性:
这依赖于具有带有更改通知的“HasErrors”属性的绑定对象。在我的项目中,我确保通过在项目 EndEdit 事件中引发 HasErrors 的 PropertyChanged 来更新 HasErrors 属性。
I have the same problem with the RowHeader error template not going away. I am using INotifyDataErrorInfo. Following up on the research by Fredrik Hedblad I have made a workaround; I have modified the DataGridRowHeader template to use a MultiBinding for the ValidationErrorTemplate visibility:
This relies on the bound objects having a "HasErrors" property with change notification. In my project I have ensured that the HasErrors property is updated by raising the PropertyChanged for HasErrors in the item EndEdit event.
我的解决方案是实现自定义行验证反馈,类似于 此页面位于自定义行验证反馈部分。然后行错误就会相应消失。
(我还在
DataGrid
定义中添加了RowHeaderWidth="20"
,以避免第一次出现感叹号时表格向右移动。)My solution was to implement custom row validation feedback, similar to this page under the To customize row validation feedback section. The row error then disappears appropriately.
(I also added
RowHeaderWidth="20"
to theDataGrid
definition, to avoid the table shift to the right the first time the exclamation point appears.)尝试从每个 Binding 元素中删除每个
DataGridTextColumns
的Mode=TwoWay
。try removing the
Mode=TwoWay
for each of theDataGridTextColumns
from each of the Binding elements.如果您看到越来越多的类似于 Meleak 的错误,我很想知道您的错误集合是如何填充的。在问题的 Meleaks 版本中,他在解决无效数据后看到三个错误(甚至更多)。
在我的数据验证代码中,我删除了特定错误的先前实例,然后在每次数据更改时重新添加。作为参考,这里有一个示例:
验证
管道正在验证的属性
因此,当运行属性更改处理程序时,如果 ValidationErrors 字典中存在错误,则将其删除,然后检查该值,如果不匹配,则将其删除要求,将错误添加到字典中。这有助于确保该实体验证错误字典中仅存在任何错误的一个实例。
If you are seeing an increasing number of errors similar to Meleak, I would be interested to know how your error collection gets populated. In Meleaks version of the problem, he sees three errors (and more) after resolving the invalid data.
In my Data Validation code, I remove the previous instance of a particular error then re-add every time the data changes. For reference, here is a sample:
The Validation Plumbing
A Property Being Validated
So, when the property Changed handler is run, if an error exists in the ValidationErrors dictionary, it is removed, then the value is checked, and it if does not match requirements, an error is added to the dictionary. This helps ensure that only one instance of any error is present in that entities validation error dictionary.
我的解决方法是不使用 Validation.Errors,而是使用 DataGridRow.Item 属性。如果您的 DataGrid 绑定到实现 IDataErrorInfo 接口的业务对象,那么您可以添加 IsNotValid 属性(或 IsValid),并确保 Error 属性返回与该对象关联的所有错误。然后自定义DataGridRowHeader的默认样式:
同样在DataGridRow样式中自定义ValidationErrorTemplate,以便它显示来自DataGridRow.Item.Error属性的错误消息。
My workaround was not to use Validation.Errors, but use DataGridRow.Item property. If your DataGrid is bound to business objects which implement IDataErrorInfo interface, then you can add IsNotValid property (or IsValid), and make sure Error property returns all errors associated with the object. Then customize default style for DataGridRowHeader:
Also in DataGridRow style customize ValidationErrorTemplate, so that it shows error message from DataGridRow.Item.Error proeprty.
最初的问题是 2011 年的,Datagrids 验证系统仍然有很多错误,以至于无法使用。我花了 2 天试图找到一个解决方案来完成以下工作:
故障实现此行为的唯一方法是放弃 RowValidation 和 CellValidation,转而使用 RowHeader 和 Styles。我从网络上的各个来源复制了以下代码。我还没有能够对此进行广泛的测试,但乍一看它看起来很有希望。
在 DataGrids XAML 中:
DataGridValidationConverter:
DataGridProps:
模型的实现:
我从更大的模型基类创建了这个最小的示例,并希望我在这里已经获得了这方面的所有重要内容。
The original Question is from 2011 and Datagrids Validation-System is still so buggy, that it is unusable. I spent 2 Days trying to find a solution to make the following work:
The only way to achieve this behaviour was to ditch RowValidation and CellValidation and instead use the RowHeader and Styles. I copied together the following code from various sources across the net. I haven't yet been able to do extensive testing of this, but it looks promising at first glances.
In DataGrids XAML:
DataGridValidationConverter:
DataGridProps:
Implementation of Model:
I created this minimal example from my bigger Model-Base-Class and hope I've got everything important for this aspect here.
我的解决方法是简单地从每个数据网格列的绑定声明中删除属性 UpdateSourceTrigger="LostFocus" 。
My workaround was to simply remove the property UpdateSourceTrigger="LostFocus" from the binding declaration in each datagridcolumn.
就我而言,当我们使用 DataGrid WPF3.5 版本时,它运行得很好。我们升级到4.0,然后它就停止重置了。在搜索SO、谷歌等之后,我偶然发现了我的解决方案。
在 DataGridTextColumn 中的绑定上设置 UpdateSourceTrigger=PropertyChanged 为我解决了这个问题。
我刚刚意识到,将其设置为正确的值时,红色感叹号并不清楚。
In my case, it worked all well and good when we were using the DataGrid WPF3.5 version. We upgraded to 4.0, then it stopped resetting. After searches on SO, google etc, I chanced upon my solution.
Setting UpdateSourceTrigger=PropertyChanged on the Binding in the DataGridTextColumn fixed it for me.
I just realised that the red exclamation mark does not clear on setting it to a correct value.
就我而言,我必须从绑定定义中删除
对我来说,它适用于这两个定义:
Validation
:CellDataInfoValidationRule 是自定义类 &在这里获取它
并且您的数据对象必须实现 IDataErrorInfo
In my case I had to remove from binding definition
For me it works with both of these definitions:
And
Validation:CellDataInfoValidationRule is custom class & get it here
And your data object must implement IDataErrorInfo
我没有使用
IDataErrorInfo
或INotifyDataErrorInfo
,我的解决方案是将绑定从UpdateSourceTrigger="PropertyChanged"
更改为UpdateSourceTrigger="LostFocus 如果您在 DataGrid 列定义
中使用 ValidationRules,并且您需要在属性更改(在 UI 或属性中)时运行验证规则,请查看设置
ValidatesOnTargetUpdated=
ValidationRule
XAML 示例中的“True”:
I am not using
IDataErrorInfo
orINotifyDataErrorInfo
and my solution was to change my bindings fromUpdateSourceTrigger="PropertyChanged"
toUpdateSourceTrigger="LostFocus"
This was the only thing thatIf you are using ValidationRules in your DataGrid column defintion and you need the validation rules to run when ever the property changes (in the UI or the property) look into setting
ValidatesOnTargetUpdated="True"
on yourValidationRule
XAML Example:
我的场景是这样的:
IDataErrorInfo
基于 WPF DataGrid 实用示例 - 使用 IDataErrorInfo 进行验证,使用 IDataErrorInfo 组合了模型中的所有错误。
ValidatesOnDataErrors=True
、ValidatesOnExceptions=True
、NotifyOnValidationError=True
(我开始使用的)这导致对我的验证引擎的多次访问,并最终离开我的 DataGrid 处于不一致状态(即使行有效,行标题上也会出现错误通知)。
解决方案是从绑定中删除开关(第 3 点)。
我建议通读 也清除 DataGrid 行验证错误。
My scenario was like this:
IDataErrorInfo
Custom Row Validation rule based on WPF DataGrid Practical Examples -Validation with IDataErrorInfo , that combined all errors from Model using IDataErrorInfo.
ValidatesOnDataErrors=True
,ValidatesOnExceptions=True
,NotifyOnValidationError=True
within the binding (which I started with)This caused multiple access to my validation Engine and eventualy left my
DataGrid
in inconsistent state (Error notification on row header even when row Valid).The solution was to remove switches from the binding (point 3.)
I suggest reading through Clearing a DataGrid row validation error too.
我使用了这种技术,它取消了 RowValidationRules,而是使用视图模型中的属性验证。这需要静态变量和数据注释:
I have used this technique which do away with RowValidationRules and instead use the property validations in a viewmodel. This requires static variables and data annotations :