// Copied from DataAnnotationsModelBinder because it was internal and I needed to override OnPropertyValidating above
        protected static string GetDisplayName(PropertyDescriptor descriptor)
        {
            var displayAttribute = descriptor.GetAttribute<DisplayAttribute>();
            if (displayAttribute != null && !String.IsNullOrEmpty(displayAttribute.Name)) {
                return displayAttribute.Name;
            }

            var displayNameAttribute = descriptor.GetAttribute<DisplayNameAttribute>();
            if (displayNameAttribute != null && !String.IsNullOrEmpty(displayNameAttribute.DisplayName)) {
                return displayNameAttribute.DisplayName;
            }

            return descriptor.Name;
        }
        /// <summary>
        /// Converts a data value. Looks for the <see cref="DisplayFormatAttribute"/> to determine
        /// if empty strings should be converted to nulls (true by default).
        /// </summary>
        /// <param name="propertyDescriptor">The property's property descriptor</param>
        /// <param name="value">The original value</param>
        /// <returns>The converted value</returns>
        internal static object ConvertValue(PropertyDescriptor propertyDescriptor,
            object value)
        {
            var displayFormatAttribute = propertyDescriptor.GetAttribute<DisplayFormatAttribute>();
            if ((displayFormatAttribute == null || displayFormatAttribute.ConvertEmptyStringToNull) && Object.Equals(value, String.Empty)) {
                return null;
            }

            return value;
        }
        protected virtual void Describe(PropertyGridProperty property, PropertyDescriptor descriptor)
        {
            if (property == null)
                throw new ArgumentNullException("property");

            if (descriptor == null)
                throw new ArgumentNullException("descriptor");

            property.Descriptor = descriptor;
            property.Name = descriptor.Name;
            property.PropertyType = descriptor.PropertyType;

            // unset by default. conversion service does the default job
            //property.Converter = descriptor.Converter;

            property.Category = string.IsNullOrWhiteSpace(descriptor.Category) || descriptor.Category.EqualsIgnoreCase(CategoryAttribute.Default.Category) ? Grid.DefaultCategoryName : descriptor.Category;
            property.IsReadOnly = descriptor.IsReadOnly;
            property.Description = descriptor.Description;
            property.DisplayName = descriptor.DisplayName;
            if (property.DisplayName == descriptor.Name)
            {
                property.DisplayName = DecamelizationService.Decamelize(property.DisplayName);
            }

            property.IsEnum = descriptor.PropertyType.IsEnum;
            property.IsFlagsEnum = descriptor.PropertyType.IsEnum && Extensions.IsFlagsEnum(descriptor.PropertyType);

            DefaultValueAttribute att = descriptor.GetAttribute<DefaultValueAttribute>();
            property.HasDefaultValue = att != null;
            property.DefaultValue = att != null ? att.Value : null;

            PropertyGridOptionsAttribute options = descriptor.GetAttribute<PropertyGridOptionsAttribute>();
            if (options != null)
            {
                if (options.SortOrder != 0)
                {
                    property.SortOrder = options.SortOrder;
                }

                property.IsEnum = options.IsEnum;
                property.IsFlagsEnum = options.IsFlagsEnum;
            }

            AddDynamicProperties(descriptor.Attributes.OfType<PropertyGridAttribute>(), property.Attributes);
            AddDynamicProperties(descriptor.PropertyType.GetAttributes<PropertyGridAttribute>(), property.TypeAttributes);
        }
        public virtual PropertyGridProperty CreateProperty(PropertyDescriptor descriptor)
        {
            if (descriptor == null)
                throw new ArgumentNullException("descriptor");

            bool forceReadWrite = false;
            PropertyGridProperty property = null;
            PropertyGridOptionsAttribute options = descriptor.GetAttribute<PropertyGridOptionsAttribute>();
            if (options != null)
            {
                forceReadWrite = options.ForceReadWrite;
                if (options.PropertyType != null)
                {
                    property = (PropertyGridProperty)Activator.CreateInstance(options.PropertyType, this);
                }
            }

            if (property == null)
            {
                options = descriptor.PropertyType.GetAttribute<PropertyGridOptionsAttribute>();
                if (options != null)
                {
                    if (!forceReadWrite)
                    {
                        forceReadWrite = options.ForceReadWrite;
                    }
                    if (options.PropertyType != null)
                    {
                        property = (PropertyGridProperty)Activator.CreateInstance(options.PropertyType, this);
                    }
                }
            }

            if (property == null)
            {
                property = CreateProperty();
            }

            Describe(property, descriptor);
            if (forceReadWrite)
            {
                property.IsReadOnly = false;
            }
            property.OnDescribed();
            property.RefreshValueFromDescriptor();
            return property;
        }