开发者

Mimicking Validation Behaviour without Validation

We have several data objects in our application that wind up bound to grids. We have them implementing the IDataErrorInfo interface, so that by adding error messages to the properties, we see the rowheader change style and the DataGridCells gain a red border. All well and good.

We now have an additional requirement that rather than merely having Errors, we have Errors and Warnings. Warnings are identical to errors except that they should produce a yellow border instead of a red one.

We created a new interface, IDataWarningInfo, based on IDataErrorInfo. Works fine. I can access it at runtime, I have RowValidatiionRules that that are able to access it, and set the yellow row header instead of the red one, the appropriate tooltip, etc. What I'm missing is the ability to set a given cell's border to yellow, on the basis that it is databound to a property where that property has a warning message.

I could retrieve that warning message by passing the name of the databound pro开发者_如何学Pythonperty back to the interface; I suspect that under the hood, the Validation code is doing exactly that. What I'm missing is how to do that in XAML. Specifically, I think I need to apply a Style to a cell, where that Style contains a DataTrigger that somehow passes to the object the name of the DataBound property, and then if the result is different from null, applies a few Setters to the Cell.

Does anyone know how to achieve this?


I have a class with an attached property for which dependencyproperty to validate. Then it uses DependencyPropertyDescriptor to attach an event to that dependencyproperty's change event.

Then when it changes, it looks through the bindings, runs the validation rules and sets the validation errors for the property without commiting the binding.

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

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜