Проверка WPF: удаление всех ошибок проверки - PullRequest
7 голосов
/ 30 июня 2010

У меня есть 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, и я хочу сделать это глобально для всех них.

Должен ли я так или иначе пройтись по Визуальному дереву (что на самом деле мне не нравится) или есть какое-то лучшее решение для этого?

Ответы [ 4 ]

2 голосов
/ 14 ноября 2012

Это то, для чего предназначена BindingGroup ... Вы устанавливаете BindingGroup для контейнера всех элементов управления, например, панель, которая содержит их. Это приведет к задержке обновлений DataContext до тех пор, пока вы не вызовете UpdateSources в BindingGroup. Если вы хотите сбросить ввод пользователя, вместо этого вы бы вызвали метод CancelEdit, и группа BindingGroup сбросила бы все элементы управления в контейнере до (все еще неизменных) значений DataContext.

1 голос
/ 04 октября 2012

У меня была такая же проблема. Несколько проверенных элементов управления на странице. Я нашел / сделал это решение для обновления (и очистки всей проверки) потомков объекта 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;
        }
    }
}
1 голос
/ 30 июня 2010

Почему бы вам просто не активировать NotifyPropertyChanged для всех свойств вашего источника данных?Это обновит привязку, и элементы управления пользовательского интерфейса должны получить значения из datacontext (которые действительны, поэтому ошибки проверки будут удалены)?

0 голосов
/ 18 июля 2012

Я не уверен, что вы подразумеваете под

Я установил DataContext в конструкторе и не хочу его менять (DataContext = null мне тогда не поможет)

Как правило, чтобы сбросить все привязки в форме, вы делаете следующее: (при условии, что контроллер для разводки представлений / моделей представления, в противном случае просто используйте кодовый вид в представлении.)

var dataContext = view.DataContext;
view.DataContext = null;
view.DataContext = dataContext;

Он не меняет его на новый контекст данных, он просто удаляет контекст данных и перезагружает его.Это запускает все привязки для повторной загрузки.

...