在没有验证的情况下模仿验证行为

时间:2010-09-28 13:45:07

标签: .net wpf validation triggers styles

我们的应用程序中有几个数据对象最终绑定到网格。我们让他们实现了IDataErrorInfo接口,这样通过向属性添加错误消息,我们看到了rowheader更改样式,DataGridCells获得了红色边框。一切都很好。

我们现在有一个额外的要求,我们有错误和警告,而不仅仅是错误。警告与错误相同,只是它们应该产生黄色边框而不是红色边框。

我们基于IDataErrorInfo创建了一个新的接口IDataWarningInfo。工作良好。我可以在运行时访问它,我有能够访问它的RowValidatiionRules,并设置黄色行标题而不是红色标题,相应的工具提示等。我缺少的是设置给定单元格边框的能力为黄色,因为它被数据绑定到属性,其中该属性具有警告消息。

我可以通过将数据绑定属性的名称传递回接口来检索该警告消息;我怀疑在底层,验证代码正是这样做的。我缺少的是如何在XAML中做到这一点。具体来说,我认为我需要将一个Style应用于一个单元格,其中该Style包含一个DataTrigger,它以某种方式将对象的名称传递给DataBound属性,然后如果结果与null不同,则将一些Setter应用于Cell

有谁知道如何实现这个目标?

1 个答案:

答案 0 :(得分:2)

我有一个带有附加属性的类,要验证的依赖项属性。然后它使用DependencyPropertyDescriptor将事件附加到该dependencyproperty的更改事件。

然后当它发生变化时,它会查看绑定,运行验证规则并为属性设置验证错误,而不会提交绑定。

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);
    }
}