WPF Validation: Clearing all validation errors

I have a WPF UserControl with many other controls inside of it. TextBoxes are among these. Every TextBox has its own validation:

<TextBox>
    <TextBox.Text>
        <Binding Path="MyPath" StringFormat="{}{0:N}" NotifyOnValidationError="True">
            <Binding.ValidationRules>
                <r:MyValidationRule ValidationType="decimal" />
            </Binding.ValidationRules>
        </Binding>
    <TextBox.Text>
<TextBox>

a

Now suppose the user types some invalid characters into them. They will all become highlighted red.

Now I want to reset all the validation errors (from the incorrect input) and set the recent correct values coming from DataContext .

I set the DataContext in the constructor and I don't want to change it (DataContext = null won't help me then):

DataContext = _myDataContext = new MyDataContext(..);

What I've already found are these classes:

Validation.ClearInvalid(..)
BindingExpression.UpdateTarget();

I think these classes could help me, but they require the Binding of a concrete FrameworkElement and I want to do it globally for all of them.

Should I anyhow iterate through the Visual Tree (which is really what I don't like) or is there any better solution for this?


This is what a BindingGroup is for... You'd set a BindingGroup on a container of all the controls, eg the panel that contains them. This would cause the updates to the DataContext to be held until you call UpdateSources on the BindingGroup. If you want to reset the user's input, you'd call CancelEdit instead, and the BindingGroup would reset all controls inside the container to the (still unchanged) values of the DataContext.


Why won't you just trigger NotifyPropertyChanged for all the properties of your data source? This will update binding and UI controls should get values from datacontext (which are valid, thus validation errors will be cleared)?


I had the same problem. Multiple validated controls on a page. I found/made this solution to update (and clear all validation from) the descentents of a 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/46616.html

上一篇: 400通过JQuery使用WCF POST的错误请求HTTP响应

下一篇: WPF验证:清除所有验证错误