WPF验证:清除所有验证错误
我有一个WPF UserControl与其中的许多其他控件。 TextBoxes就是其中之一。 每个TextBox都有自己的验证:
<TextBox>
<TextBox.Text>
<Binding Path="MyPath" StringFormat="{}{0:N}" NotifyOnValidationError="True">
<Binding.ValidationRules>
<r:MyValidationRule ValidationType="decimal" />
</Binding.ValidationRules>
</Binding>
<TextBox.Text>
<TextBox>
一个
现在假设用户输入一些无效字符。 他们都会变得突出红色。
现在我想重置所有验证错误 (来自不正确的输入)并设置来自DataContext
的最近正确值 。
我在构造函数中设置了DataContext,我不想改变它(DataContext = null当时不会帮助我):
DataContext = _myDataContext = new MyDataContext(..);
我已经找到了这些类:
Validation.ClearInvalid(..)
BindingExpression.UpdateTarget();
我认为这些类可以帮助我,但是他们需要Binding
一个具体的FrameworkElement
,我想为它们全局进行。
我应该反复通过Visual Tree(这真的是我不喜欢的)还是有更好的解决方案呢?
这就是BindingGroup的用途......你可以在所有控件的容器上设置一个BindingGroup,例如包含它们的面板。 这会导致DataContext的更新被保留,直到您调用BindingGroup上的UpdateSources。 如果你想重置用户的输入,你可以调用CancelEdit,而BindingGroup会将容器内的所有控件重置为DataContext的(仍未改变的)值。
为什么你不会为数据源的所有属性触发NotifyPropertyChanged? 这将更新绑定和UI控件应该从datacontext获取值(这是有效的,因此验证错误将被清除)?
我有同样的问题。 多个经过验证的页面上的控件。 我发现/使这个解决方案更新(并清除所有的验证)DependencyObject的子域:
using System.Linq;
using System.Windows;
using System.Windows.Data;
using System.Windows.Media;
/// <summary>
/// Updates all binding targets where the data item is of the specified type.
/// </summary>
/// <param name="root">The root.</param>
/// <param name="depth">The depth.</param>
/// <param name="dataItemType">Type of the data item.</param>
/// <param name="clearInvalid">Clear validation errors from binding.</param>
public static void UpdateAllBindingTargets(this DependencyObject root, int depth, Type dataItemType, bool clearInvalid)
{
var bindingExpressions = EnumerateDescendentsBindingExpressions(root, depth);
foreach (BindingExpression be in bindingExpressions.Where(be => be.DataItem != null && be.DataItem.GetType() == dataItemType))
{
if (be != null)
{
be.UpdateTarget();
if (clearInvalid)
System.Windows.Controls.Validation.ClearInvalid(be);
}
}
}
/// <summary>
/// Enumerates all binding expressions on descendents.
/// </summary>
/// <param name="root">The root.</param>
/// <param name="depth">The depth.</param>
/// <returns></returns>
public static IEnumerable<BindingExpression> EnumerateDescendentsBindingExpressions(this DependencyObject root, int depth)
{
return root.EnumerateDescendents(depth).SelectMany(obj => obj.EnumerateBindingExpressions());
}
/// <summary>
/// Enumerates the descendents of the specified root to the specified depth.
/// </summary>
/// <param name="root">The root.</param>
/// <param name="depth">The depth.</param>
public static IEnumerable<DependencyObject> EnumerateDescendents(this DependencyObject root, int depth)
{
int count = VisualTreeHelper.GetChildrenCount(root);
for (int i = 0; i < count; i++)
{
var child = VisualTreeHelper.GetChild(root, i);
yield return child;
if (depth > 0)
{
foreach (var descendent in EnumerateDescendents(child, --depth))
yield return descendent;
}
}
}
/// <summary>
/// Enumerates the binding expressions of a Dependency Object.
/// </summary>
/// <param name="element">The parent element.</param>
public static IEnumerable<BindingExpression> EnumerateBindingExpressions(this DependencyObject element)
{
if (element == null)
{
throw new ArgumentNullException("element");
}
LocalValueEnumerator lve = element.GetLocalValueEnumerator();
while (lve.MoveNext())
{
LocalValueEntry entry = lve.Current;
if (BindingOperations.IsDataBound(element, entry.Property))
{
if (entry.Value is PriorityBindingExpression)
{
foreach (BindingExpression expr in ((PriorityBindingExpression)entry.Value).BindingExpressions)
yield return expr;
}
else if (entry.Value is MultiBindingExpression)
{
foreach (BindingExpression expr in ((MultiBindingExpression)entry.Value).BindingExpressions)
yield return expr;
}
else
yield return entry.Value as BindingExpression;
}
}
}
链接地址: http://www.djcxy.com/p/46615.html
上一篇: WPF Validation: Clearing all validation errors
下一篇: How to set PlatformToolset from custom property sheet in Visual Studio 2010