Имитация поведения валидации без валидации - PullRequest
3 голосов
/ 28 сентября 2010

В нашем приложении есть несколько объектов данных, которые привязаны к сеткам.У нас есть они, реализующие интерфейс IDataErrorInfo, так что, добавляя сообщения об ошибках в свойства, мы видим стиль изменения заголовка строки и DataGridCells получают красную рамку.Все хорошо.

Теперь у нас есть дополнительное требование: вместо ошибок есть ошибки и предупреждения.Предупреждения идентичны ошибкам, за исключением того, что они должны создавать желтую границу вместо красной.

Мы создали новый интерфейс, IDataWarningInfo, основанный на IDataErrorInfo.Работает отлично.Я могу получить к нему доступ во время выполнения, у меня есть RowValidatiionRules, которые могут получить к нему доступ, и установить желтый заголовок строки вместо красного, соответствующую всплывающую подсказку и т. Д. Что мне не хватает, так это возможность установить границу данной ячейкижелтому цвету на том основании, что оно привязано к свойству, в котором это свойство имеет предупреждающее сообщение.

Я мог бы получить это предупреждающее сообщение, передав имя интерфейса привязки данных обратно в интерфейс;Я подозреваю, что под капотом код проверки делает именно это.Чего мне не хватает, так это сделать в XAML.В частности, я думаю, что мне нужно применить стиль к ячейке, где этот стиль содержит DataTrigger, который каким-то образом передает объекту имя свойства DataBound, а затем, если результат отличается от нуля, применяет несколько сеттеров к ячейке.

Кто-нибудь знает, как этого добиться?

1 Ответ

2 голосов
/ 23 февраля 2011

У меня есть класс с прикрепленным свойством, для которого проверяется зависимость свойства.Затем он использует DependencyPropertyDescriptor для присоединения события к событию изменения этого зависимого свойства.

Затем, когда он изменяется, он просматривает привязки, запускает правила проверки и устанавливает ошибки проверки для свойства без фиксации привязки.

public static class ValidatingControlBehavior
{
    /// <summary>
    /// Defines the ValidatingProperty dependency property.
    /// </summary>
    public static readonly DependencyProperty ValidatingPropertyProperty = DependencyProperty.RegisterAttached("ValidatingProperty", typeof(DependencyProperty), typeof(ValidatingControlBehavior), 
        new PropertyMetadata(ValidatingControlBehavior.ValidatingPropertyProperty_PropertyChanged));

    /// <summary>
    /// Attaches the event.
    /// </summary>
    /// <param name="control">The control.</param>
    /// <param name="dependencyProperty">The dependency property.</param>
    private static void AttachEvent(Control control, DependencyProperty dependencyProperty)
    {
        DependencyPropertyDescriptor.FromProperty(dependencyProperty, typeof(Control)).AddValueChanged(control, ValidatingControlBehavior.Control_PropertyChanged);
        control.ForceValidation(dependencyProperty);
    }

    /// <summary>
    /// Handles the PropertyChanged event of the Control control.
    /// </summary>
    /// <param name="sender">The source of the event.</param>
    /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
    private static void Control_PropertyChanged(object sender, EventArgs e)
    {
        Control control = (Control)sender;
        control.ForceValidation(ValidatingControlBehavior.GetValidatingProperty(control));
    }

    /// <summary>
    /// Forces the validation.
    /// </summary>
    /// <param name="dependencyObject">The dependency object.</param>
    /// <param name="dependencyProperty">The dependency property.</param>
    private static void ForceValidation(this DependencyObject dependencyObject, DependencyProperty dependencyProperty)
    {
        BindingExpressionBase expression = BindingOperations.GetBindingExpressionBase(dependencyObject, dependencyProperty);
        Collection<ValidationRule> validationRules;
        if (expression != null)
        {
            MultiBinding multiBinding;
            Binding binding = expression.ParentBindingBase as Binding;
            if (binding != null)
            {
                validationRules = binding.ValidationRules;
            }
            else if ((multiBinding = expression.ParentBindingBase as MultiBinding) != null)
            {
                validationRules = multiBinding.ValidationRules;
            }
            else
            {
                return;
            }
            for (int i = 0; i < validationRules.Count; i++)
            {
                ValidationRule rule = validationRules[i];
                ValidationResult result = rule.Validate(dependencyObject.GetValue(dependencyProperty), CultureInfo.CurrentCulture);
                if (!result.IsValid)
                {
                    Validation.MarkInvalid(expression, new ValidationError(rule, expression.ParentBindingBase, result.ErrorContent, null));
                    return;
                }
            }
            Validation.ClearInvalid(expression);
        }
    }

    /// <summary>
    /// Detaches the event.
    /// </summary>
    /// <param name="control">The control.</param>
    /// <param name="dependencyProperty">The dependency property.</param>
    private static void DetachEvent(Control control, DependencyProperty dependencyProperty)
    {
        DependencyPropertyDescriptor.FromProperty(dependencyProperty, typeof(Control)).RemoveValueChanged(control, ValidatingControlBehavior.Control_PropertyChanged);
    }

    /// <summary>
    /// Handles the PropertyChanged event of the ValidatingPropertyProperty control.
    /// </summary>
    /// <param name="d">The source of the event.</param>
    /// <param name="e">The <see cref="System.Windows.DependencyPropertyChangedEventArgs"/> instance containing the event data.</param>
    private static void ValidatingPropertyProperty_PropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        Control control = d as Control;
        if (control != null)
        {
            if (e.OldValue != null)
            {
                ValidatingControlBehavior.DetachEvent(control, (DependencyProperty)e.OldValue);
            }
            if (e.NewValue != null)
            {
                ValidatingControlBehavior.AttachEvent(control, (DependencyProperty)e.NewValue);
            }
        }
    }

    /// <summary>
    /// Gets the validating property.
    /// </summary>
    /// <param name="control">The control.</param>
    /// <returns>
    /// Dependency property.
    /// </returns>
    public static DependencyProperty GetValidatingProperty(Control control)
    {
        return (DependencyProperty)control.GetValue(ValidatingControlBehavior.ValidatingPropertyProperty);
    }

    /// <summary>
    /// Sets the validating property.
    /// </summary>
    /// <param name="control">The control.</param>
    /// <param name="validatingProperty">The validating property.</param>
    public static void SetValidatingProperty(Control control, DependencyProperty validatingProperty)
    {
        control.SetValue(ValidatingControlBehavior.ValidatingPropertyProperty, validatingProperty);
    }
}
...