public static void Length <TOwnerVM, TTargetVM>(
     this PropertyValidatorBuilder <TOwnerVM, TTargetVM, string> builder,
     int maximumLength,
     string errorMessage,
     object details = null
     )
     where TOwnerVM : IViewModel
     where TTargetVM : IViewModel
 {
     builder.Custom((args) => {
         if (args.Value != null && args.Value.Length > maximumLength)
         {
             args.AddError(errorMessage.FormatWith(maximumLength), details);
         }
     });
 }
        public static void RegexValidation <TOwnerVM, TTargetVM>(
            this PropertyValidatorBuilder <TOwnerVM, TTargetVM, string> builder,
            string regexPattern,
            string errorMessage,
            object details = null
            )
            where TOwnerVM : IViewModel
            where TTargetVM : IViewModel
        {
            Regex regex = new Regex(regexPattern);

            builder.Custom((args) => {
                if (!(String.IsNullOrEmpty(args.Value) || regex.IsMatch(args.Value)))
                {
                    args.AddError(errorMessage, details);
                }
            });
        }
        public static void HasValue <TOwnerVM, TTargetVM, TValue>(
            this PropertyValidatorBuilder <TOwnerVM, TTargetVM, TValue> builder,
            string errorMessage,
            object details = null
            )
            where TOwnerVM : IViewModel
            where TTargetVM : IViewModel
        {
            builder.Custom((args) => {
                bool empty =
                    (args.Value is string && String.IsNullOrWhiteSpace(args.Value as string)) ||
                    Object.Equals(args.Value, null);

                if (empty)
                {
                    args.AddError(errorMessage, details);
                }
            });
        }
        public static void Max <TOwnerVM, TTargetVM, TValue>(
            this PropertyValidatorBuilder <TOwnerVM, TTargetVM, TValue> builder,
            TValue max,
            string message = null,
            object details = null
            )
            where TOwnerVM : IViewModel
            where TTargetVM : IViewModel
            where TValue : IComparable
        {
            message = message ?? Localized.ValidationMax;

            builder.Custom((args) => {
                if (max.CompareTo(args.Value) < 0)
                {
                    string msg = message.FormatWith(max); // DO NOT reuse parameter!
                    args.AddError(msg, details);
                }
            });
        }
        public static void Min <TOwnerVM, TTargetVM, TValue>(
            this PropertyValidatorBuilder <TOwnerVM, TTargetVM, Nullable <TValue> > builder,
            TValue min,
            string message = null,
            object details = null
            )
            where TOwnerVM : IViewModel
            where TTargetVM : IViewModel
            where TValue : struct, IComparable
        {
            message = message ?? Localized.ValidationMin;

            builder.Custom((args) => {
                if (args.Value.HasValue &&
                    min.CompareTo(args.Value) == 1)
                {
                    string msg = message.FormatWith(min); // DO NOT reuse parameter!
                    args.AddError(msg, details);
                }
            });
        }
        public static void Min <TOwnerVM, TTargetVM, TValue>(
            this PropertyValidatorBuilder <TOwnerVM, TTargetVM, TValue> builder,
            Func <TOwnerVM, TValue> minValueSelector,
            string message = null,
            object details = null
            )
            where TOwnerVM : IViewModel
            where TTargetVM : IViewModel
            where TValue : IComparable
        {
            message = message ?? Localized.ValidationMin;

            builder.Custom((args) => {
                var minValue = minValueSelector(args.Owner);

                if (minValue.CompareTo(args.Value) == 1)
                {
                    string msg = message.FormatWith(minValue); // DO NOT reuse parameter!
                    args.AddError(msg, details);
                }
            });
        }