Asynchronous Validation of All Properties

,

As the user completes a form, individual properties are validated. To validate an entire form at once, the same approach is used; however, each property is validated, one by one, until all are validated, or until one is deemed invalid.

The IsComplete method of the DataErrorValidator attempts to validate each known property and accepts handlers that are invoked when one of the following three conditions is met:

Image completeActionThe viewmodel is complete; that is, no properties have associated data-validation errors.

Image incompleteActionThe viewmodel is incomplete; that is, one or more properties have an associated data-validation error.

Image unknownActionDetermination of the viewmodel’s completeness failed because an exception was raised.

To validate each property, the DataErrorValidator creates a list of all known property names, and as each property is validated, the property name is removed from the list, as shown in the following excerpt:

public void IsComplete(Action completeAction,
                       Action incompleteAction,
                       Action<Exception> unknownAction)
{
    this.completeAction = completeAction;
    this.incompleteAction = incompleteAction;
    this.unknownAction = unknownAction;

    try
    {
        if (!LockedOperations.TrySetTrue(
            ref isEvaluating, isEvaluatingLock))
        {
            return;
        }

        if (propertyDictionary == null)
        {
            if (completeAction != null)
            {
                completeAction();
            }
            return;
        }

        lock (waitingForPropertiesLock)
        {
            waitingForProperties.Clear();
            foreach (KeyValuePair<string, Func<object>> pair
                                                 in propertyDictionary)
            {
                waitingForProperties.Add(pair.Key);
            }
        }
        foreach (KeyValuePair<string, Func<object>> pair
            in propertyDictionary)
        {
            validator.BeginValidation(pair.Key, pair.Value());
        }
    }
    catch (Exception ex)
    {
        isEvaluating = false;
        if (unknownAction != null)
        {
            unknownAction(ex);
        }
    }
}

The LockedOperations.TrySetTrue method provides for thread safety when reading and setting the isEvaluating flag. If isEvaluating is already true, the call to the IsComplete method is ignored, as shown:

public static bool TrySetTrue(ref bool value, object valueLock)
{
    ArgumentValidator.AssertNotNull(valueLock, "valueLock");
    if (!value)
    {
        lock (valueLock)
        {
            if (!value)
            {
                value = true;
                return true;
            }
        }
    }
    return false;
}

The TrySetTrue method reduces the amount of locking related code in the IsComplete method.

When the list of property names in the IsComplete method is empty, or an exception is raised, the evaluation of the IsComplete method is deemed to be complete.

At completion, one of the three IsComplete action arguments is invoked. If the ValidationCompleteEventArgs contains an Exception, the unknownAction is invoked. If there are any data validation errors for the property, the incompleteAction is invoked. If there are no properties left to validate, the completeAction is invoked. See the following excerpt:

void HandleValidationComplete(object sender, ValidationCompleteEventArgs e)
{
    try
    {
        if (e.Exception == null)
        {
            SetPropertyErrors(e.PropertyName, e.Errors);
        }
    }
    catch (Exception ex)
    {
        Debug.WriteLine("Unable to set property error." + ex);
    }

    if (!isEvaluating)
    {
        return;
    }

    lock (isEvaluatingLock)
    {
        if (!isEvaluating)
        {
            return;
        }

        try
        {
            bool finishedEvaluating;
            lock (waitingForPropertiesLock)
            {
                waitingForProperties.Remove(e.PropertyName);
                finishedEvaluating = waitingForProperties.Count < 1;
            }

            if (e.Exception != null)
            {
                isEvaluating = false;
                if (unknownAction != null)
                {
                    unknownAction(e.Exception);
                }
            }
            if (e.Errors != null && e.Errors.Count() > 0)
            {
                isEvaluating = false;
                if (incompleteAction != null)
                {
                    incompleteAction();
                }
            }

            if (finishedEvaluating)
            {
                bool success = isEvaluating;
                isEvaluating = false;
                if (success && completeAction != null)
                {
                    completeAction();
                }
            }
        }
        catch (Exception ex)
        {
            Debug.WriteLine("Unable to validate property." + ex);
            isEvaluating = false;
        }
    }
}

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.222.116.146