I’m working on a WPF application that have some validation performed through the standard ValidationRule system employed by WPF at the UI level.

Recently I needed a way to validate (that is check the state and force the execution of any validation rule) full portions of the Visual Tree. The idea was to call a function that, given a DependencyObject would traverse the tree and force the execution of any validation rule attached to a any Binding we can find.

The first step is then find out how to get all the Dependency Properties that an object exposes; I’ve ‘googled’ a bit and found out many solution that use the DependencyObject.GetLocalValueEnumerator() method...unfortunately this one is not useful in my case, cause it doesn’t return values set in templates.

In the end I was forced to use reflection to get the dependency properties of an object and for performances reasons I decided to cache the result of those reflection calls in a dictionary.

The rest of the function is straightforward and it’s a modified version of a routine you can find on the ‘Programming WPF’ book. To force the validation to be performed instead of calling the Validation.MarkInvalid() function I choose to get the binding expression and call it’s update methods which guarantee that the associated error collection of an object is cleared if the state becomes valid again.

Here’s some code:

public static class Validator
{
   private static Dictionary<Type, List<DependencyProperty>> PropertiesReflectionChace = new Dictionary<Type, List<DependencyProperty>>();
 
   private static List<DependencyProperty> GetDPs(Type t)
   {
      if (PropertiesReflectionChace.ContainsKey(t))
         return PropertiesReflectionChace[t];
      FieldInfo[] properties = t.GetFields(BindingFlags.Public | BindingFlags.GetProperty |
           BindingFlags.Static | BindingFlags.FlattenHierarchy);
      // we cycle and store only the dependency properties
      List<DependencyProperty> dps = new List<DependencyProperty>();
 
      foreach (FieldInfo field in properties)
         if (field.FieldType == typeof(DependencyProperty))
            dps.Add((DependencyProperty)field.GetValue(null));
      PropertiesReflectionChace.Add(t, dps);
 
      return dps;
   }
 
   /// <summary>
   /// checks all the validation rule associated with objects,
   /// forces the binding to execute all their validation rules
   /// </summary>
   /// <param name="parent"></param>
   /// <returns></returns>
   public static bool IsValid(DependencyObject parent)
   {
      // Validate all the bindings on the parent
      bool valid = true;
      // get the list of all the dependency properties, we can use a level of caching to avoid to use reflection
      // more than one time for each object
      foreach (DependencyProperty dp in GetDPs(parent.GetType()))
      {
         if (BindingOperations.IsDataBound(parent, dp))
         {
            Binding binding = BindingOperations.GetBinding(parent, dp);
            if (binding.ValidationRules.Count > 0)
            {
               BindingExpression expression = BindingOperations.GetBindingExpression(parent, dp);
               switch (binding.Mode)
               {
                  case BindingMode.OneTime:
                  case BindingMode.OneWay:
                     expression.UpdateTarget();
                     break;
                  default:
                     expression.UpdateSource();
                     break;
               }
               if (expression.HasError) valid = false;
            }
         }
      }
 
      // Validate all the bindings on the children
      for (int i = 0; i != VisualTreeHelper.GetChildrenCount(parent); ++i)
      {
         DependencyObject child = VisualTreeHelper.GetChild(parent, i);
         if (!IsValid(child)) { valid = false; }
      }
 
      return valid;
   }
}

Related Content