/// <summary>
        /// Processes the value.
        /// </summary>
        /// <returns>
        /// The <see cref="object" /> representing the processed value.
        /// </returns>
        public override object ProcessValue()
        {
            object result                   = this.Value;
            var    propertyType             = this.Context.PropertyDescriptor.PropertyType;
            var    propertyIsEnumerableType = Direction == EnumerableConvertionDirection.Automatic
                ? propertyType.IsEnumerableType() &&
                                              !(propertyType == typeof(string))
                : Direction == EnumerableConvertionDirection.ToEnumerable;

            if (this.Value != null)
            {
                var valueType             = this.Value.GetType();
                var valueIsEnumerableType = valueType.IsEnumerableType() &&
                                            !(this.Value is string);

                if (propertyIsEnumerableType)
                {
                    if (!valueIsEnumerableType)
                    {
                        // Property is enumerable, but value isn't, so make enumerable
                        var arr = Array.CreateInstance(valueType, 1);
                        arr.SetValue(this.Value, 0);
                        result = arr;
                    }
                }
                else
                {
                    if (valueIsEnumerableType)
                    {
                        // Property is not enumerable, but value is, so grab first item
                        var enumerator = ((IEnumerable)this.Value).GetEnumerator();
                        result = enumerator.MoveNext() ? enumerator.Current : null;
                    }
                }
            }
            else
            {
                if (propertyIsEnumerableType)
                {
                    if (propertyType.IsInterface && !propertyType.IsEnumerableOfKeyValueType())
                    {
                        // Value is null, but property is enumerable interface, so return empty enumerable
                        result = EnumerableInvocations.Empty(propertyType.GenericTypeArguments.First());
                    }
                    else
                    {
                        // Concrete enumerables cannot be cast from Array so we create an instance and return it
                        // if we know it has an empty constructor.
                        var constructorParams = propertyType.GetConstructorParameters();
                        if (constructorParams != null && constructorParams.Length == 0)
                        {
                            // Internally this uses Activator.CreateInstance which is heavily optimized.
                            result = propertyType.GetInstance();
                        }
                    }
                }
            }

            return(result);
        }
        /// <summary>
        /// Processes the value.
        /// </summary>
        /// <returns>
        /// The <see cref="object" /> representing the processed value.
        /// </returns>
        /// <exception cref="System.NotImplementedException"></exception>
        public override object ProcessValue()
        {
            object result = Value;

            var propertyIsEnumerableType = Context.PropertyDescriptor.PropertyType.IsEnumerableType() &&
                                           !Context.PropertyDescriptor.PropertyType.IsEnumerableOfKeyValueType() &&
                                           !(Context.PropertyDescriptor.PropertyType == typeof(string));

            if (Value != null)
            {
                var valueIsEnumerableType = Value.GetType().IsEnumerableType() &&
                                            !Value.GetType().IsEnumerableOfKeyValueType() &&
                                            !(Value is string);

                if (propertyIsEnumerableType)
                {
                    if (!valueIsEnumerableType)
                    {
                        // Property is enumerable, but value isn't, so make enumerable
                        var arr = Array.CreateInstance(Value.GetType(), 1);
                        arr.SetValue(Value, 0);
                        result = arr;
                    }
                }
                else
                {
                    if (valueIsEnumerableType)
                    {
                        // Property is not enumerable, but value is, so grab first item
                        var enumerator = ((IEnumerable)Value).GetEnumerator();
                        result = enumerator.MoveNext() ? enumerator.Current : null;
                    }
                }
            }
            else
            {
                if (propertyIsEnumerableType)
                {
                    // Value is null, but property is enumerable, so return empty enumerable
                    result = EnumerableInvocations.Empty(Context.PropertyDescriptor.PropertyType.GenericTypeArguments.First());
                }
            }

            return(result);
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Converts the given object to the type of this converter, using the specified context and culture information.
        /// </summary>
        /// <param name="context">An <see cref="T:System.ComponentModel.ITypeDescriptorContext" /> that provides a format context.</param>
        /// <param name="culture">The <see cref="T:System.Globalization.CultureInfo" /> to use as the current culture.</param>
        /// <param name="value">The <see cref="T:System.Object" /> to convert.</param>
        /// <returns>
        /// An <see cref="T:System.Object" /> that represents the converted value.
        /// </returns>
        public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
        {
            // ReSharper disable once ConditionIsAlwaysTrueOrFalse
            if (context == null || context.PropertyDescriptor == null)
            {
                return(Enumerable.Empty <object>());
            }

            var propertyType  = context.PropertyDescriptor.PropertyType;
            var isGenericType = propertyType.IsGenericType;
            var targetType    = isGenericType
                                ? propertyType.GenericTypeArguments.First()
                                : propertyType;

            if (value.IsNullOrEmptyString())
            {
                return(EnumerableInvocations.Empty(targetType));
            }

            // DictionaryPublishedContent
            IPublishedContent content = value as IPublishedContent;

            if (content != null)
            {
                // Use the id so we get folder sanitation.
                return(this.ConvertMediaFromInt(content.Id, targetType, culture));
            }

            // If a single item is selected, this is passed as an int, not a string.
            if (value is int)
            {
                var id = (int)value;
                return(this.ConvertMediaFromInt(id, targetType, culture).YieldSingleItem());
            }

            var s = value as string;

            if (!string.IsNullOrWhiteSpace(s))
            {
                var multiMediaPicker = EnumerableInvocations.Empty(targetType);

                int n;
                var nodeIds =
                    XmlHelper.CouldItBeXml(s)
                    ? s.GetXmlIds()
                    : s
                    .ToDelimitedList()
                    .Select(x => int.TryParse(x, NumberStyles.Any, culture, out n) ? n : -1)
                    .Where(x => x > 0)
                    .ToArray();

                if (nodeIds.Any())
                {
                    multiMediaPicker = nodeIds.ForEach(i => this.ConvertMediaFromInt(i, targetType, culture));
                }

                return(multiMediaPicker);
            }

            return(base.ConvertFrom(context, culture, value));
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Set the typed value to the given instance.
        /// </summary>
        /// <param name="content">The <see cref="IPublishedContent"/> to convert.</param>
        /// <param name="culture">The <see cref="CultureInfo"/></param>
        /// <param name="propertyInfo">The <see cref="PropertyInfo"/> property info associated with the type.</param>
        /// <param name="propertyValue">The property value.</param>
        /// <param name="instance">The instance to assign the value to.</param>
        /// <returns>The strong typed converted value for the given property.</returns>
        private static object GetConvertedValue(
            IPublishedContent content,
            CultureInfo culture,
            PropertyInfo propertyInfo,
            object propertyValue,
            object instance)
        {
            // Process the value.
            object result       = null;
            var    propertyType = propertyInfo.PropertyType;
            var    typeInfo     = propertyType.GetTypeInfo();

            // This should return false against typeof(string) etc also.
            var propertyIsEnumerableType = propertyType.IsCastableEnumerableType();

            // Try any custom type converters first.
            // 1: Check the property.
            // 2: Check any type arguments in generic enumerable types.
            // 3: Check the type itself.
            var converterAttribute =
                propertyInfo.GetCustomAttribute <TypeConverterAttribute>()
                ?? (propertyIsEnumerableType ? typeInfo.GenericTypeArguments.First().GetCustomAttribute <TypeConverterAttribute>(true)
                                             : propertyType.GetCustomAttribute <TypeConverterAttribute>(true));

            if (converterAttribute != null && converterAttribute.ConverterTypeName != null)
            {
                // Time custom conversions.
                using (DittoDisposableTimer.DebugDuration <object>(string.Format("Custom TypeConverter ({0}, {1})", content.Id, propertyInfo.Name)))
                {
                    // Get the custom converter from the attribute and attempt to convert.
                    var converterType = Type.GetType(converterAttribute.ConverterTypeName);
                    if (converterType != null)
                    {
                        var converter = converterType.GetDependencyResolvedInstance() as TypeConverter;

                        if (converter != null)
                        {
                            // Create context to pass to converter implementations.
                            // This contains the IPublishedContent and the currently converting property descriptor.
                            var descriptor = TypeDescriptor.GetProperties(instance)[propertyInfo.Name];
                            var context    = new DittoTypeConverterContext
                            {
                                ConversionType     = instance.GetType(),
                                Instance           = content,
                                PropertyDescriptor = descriptor
                            };

                            Type propertyValueType = null;
                            if (propertyValue != null)
                            {
                                propertyValueType = propertyValue.GetType();
                            }

                            // We're deliberately passing null.
                            // ReSharper disable once AssignNullToNotNullAttribute
                            if (converter.CanConvertFrom(context, propertyValueType))
                            {
                                object converted = converter.ConvertFrom(context, culture, propertyValue);

                                if (converted != null)
                                {
                                    // Handle Typeconverters returning single objects when we want an IEnumerable.
                                    // Use case: Someone selects a folder of images rather than a single image with the media picker.
                                    var convertedType = converted.GetType();

                                    if (propertyIsEnumerableType)
                                    {
                                        var parameterType = typeInfo.GenericTypeArguments.First();

                                        // Some converters return an IEnumerable so we check again.
                                        if (!convertedType.IsEnumerableType())
                                        {
                                            // Using 'Cast' to convert the type back to IEnumerable<T>.
                                            object enumerablePropertyValue = EnumerableInvocations.Cast(
                                                parameterType,
                                                converted.YieldSingleItem());

                                            result = enumerablePropertyValue;
                                        }
                                        else
                                        {
                                            // Nothing is strong typed anymore.
                                            result = EnumerableInvocations.Cast(parameterType, (IEnumerable)converted);
                                        }
                                    }
                                    else
                                    {
                                        // Return single expected items from converters returning an IEnumerable.
                                        // Check for key/value pairs and strings.
                                        if (convertedType.IsEnumerableType() &&
                                            !convertedType.IsEnumerableOfKeyValueType() &&
                                            !(convertedType == typeof(string) && propertyType == typeof(string)))
                                        {
                                            // Use 'FirstOrDefault' to convert the type back to T.
                                            result = EnumerableInvocations.FirstOrDefault(
                                                propertyType,
                                                (IEnumerable)converted);
                                        }
                                        else
                                        {
                                            result = converted;
                                        }
                                    }
                                }
                                else
                                {
                                    // Ensure we pass back an empty enumerable if the expected output is an enumerable.
                                    // and null has been returned by the type converter.
                                    if (propertyIsEnumerableType)
                                    {
                                        result = EnumerableInvocations.Empty(typeInfo.GenericTypeArguments.First());
                                    }
                                }
                            }
                            else if (propertyType.IsInstanceOfType(propertyValue))
                            {
                                // If the TypeConverter's `CanConvertFrom` has returned false,
                                // then we can check if the value is the same type as the target type.
                                result = propertyValue;
                            }
                        }
                    }
                }
            }
            else if (propertyType == typeof(HtmlString))
            {
                // Handle Html strings so we don't have to set the attribute.
                var converterType = typeof(DittoHtmlStringConverter);
                var converter     = converterType.GetDependencyResolvedInstance() as TypeConverter;

                if (converter != null)
                {
                    // This contains the IPublishedContent and the currently converting property descriptor.
                    var descriptor = TypeDescriptor.GetProperties(instance)[propertyInfo.Name];
                    var context    = new DittoTypeConverterContext
                    {
                        ConversionType     = instance.GetType(),
                        Instance           = content,
                        PropertyDescriptor = descriptor
                    };

                    Type propertyValueType = null;
                    if (propertyValue != null)
                    {
                        propertyValueType = propertyValue.GetType();
                    }

                    // We're deliberately passing null.
                    // ReSharper disable once AssignNullToNotNullAttribute
                    if (converter.CanConvertFrom(context, propertyValueType))
                    {
                        result = converter.ConvertFrom(context, culture, propertyValue);
                    }
                }
            }
            else if (propertyType.IsInstanceOfType(propertyValue))
            {
                // Simple types
                result = propertyValue;
            }
            else if (propertyValue is IPublishedContent && propertyType.IsClass)
            {
                // If the property value is an IPublishedContent, then we can use Ditto to map to the target type.
                result = ((IPublishedContent)propertyValue).As(propertyType);
            }
            else if (propertyValue != null &&
                     propertyValue.GetType().IsEnumerableOfType(typeof(IPublishedContent)) &&
                     propertyType.IsEnumerable() &&
                     propertyType.GetEnumerableType() != null &&
                     propertyType.GetEnumerableType().IsClass)
            {
                // If the property value is IEnumerable<IPublishedContent>, then we can use Ditto to map to the target type.
                result = ((IEnumerable <IPublishedContent>)propertyValue).As(propertyType.GetEnumerableType());
            }
            else
            {
                using (DittoDisposableTimer.DebugDuration <object>(string.Format("TypeConverter ({0}, {1})", content.Id, propertyInfo.Name)))
                {
                    var convert = propertyValue.TryConvertTo(propertyType);
                    if (convert.Success)
                    {
                        result = convert.Result;
                    }
                }
            }

            return(result);
        }
Ejemplo n.º 5
0
        /// <summary>
        /// Converts the given object to the type of this converter, using the specified context and culture information.
        /// </summary>
        /// <param name="context">An <see cref="T:System.ComponentModel.ITypeDescriptorContext" /> that provides a format context.</param>
        /// <param name="culture">The <see cref="T:System.Globalization.CultureInfo" /> to use as the current culture.</param>
        /// <param name="value">The <see cref="T:System.Object" /> to convert.</param>
        /// <returns>
        /// An <see cref="T:System.Object" /> that represents the converted value.
        /// </returns>
        public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
        {
            // ReSharper disable once ConditionIsAlwaysTrueOrFalse
            if (context == null || context.PropertyDescriptor == null)
            {
                // There's no way to determine the type here.
                return(null);
            }

            var propertyType  = context.PropertyDescriptor.PropertyType;
            var isGenericType = propertyType.IsGenericType;
            var targetType    = isGenericType
                                ? propertyType.GenericTypeArguments.First()
                                : propertyType;

            if (value.IsNullOrEmptyString())
            {
                if (isGenericType)
                {
                    return(EnumerableInvocations.Empty(targetType));
                }

                return(null);
            }

            // If a single item is selected, this comes back as an int, not a string.
            if (value is int)
            {
                var id = (int)value;

                // CheckBoxList, ListBox
                if (targetType != null)
                {
                    return(this.ConvertContentFromInt(id, targetType, culture).YieldSingleItem());
                }

                // AutoComplete, DropDownList, RadioButton
                return(this.ConvertContentFromInt(id, propertyType, culture));
            }

            if (value != null)
            {
                string s = value as string ?? value.ToString();
                if (!string.IsNullOrWhiteSpace(s))
                {
                    int n;
                    var nodeIds = s
                                  .ToDelimitedList()
                                  .Select(x => int.TryParse(x, NumberStyles.Any, culture, out n) ? n : -1)
                                  .Where(x => x > 0)
                                  .ToArray();

                    if (nodeIds.Any())
                    {
                        var ultimatePicker = new List <IPublishedContent>();

                        // ReSharper disable once LoopCanBeConvertedToQuery
                        foreach (var nodeId in nodeIds)
                        {
                            var item = UmbracoContext.Current.ContentCache.GetById(nodeId);

                            if (item != null)
                            {
                                ultimatePicker.Add(item);
                            }
                        }

                        // CheckBoxList, ListBox
                        if (isGenericType)
                        {
                            return(ultimatePicker.As(targetType, culture));
                        }

                        // AutoComplete, DropDownList, RadioButton
                        return(ultimatePicker.As(targetType, culture).FirstOrDefault());
                    }
                }
            }

            return(base.ConvertFrom(context, culture, value));
        }
Ejemplo n.º 6
0
        /// <summary>
        /// Converts the given object to the type of this converter, using the specified context and culture information.
        /// </summary>
        /// <param name="context">An <see cref="T:System.ComponentModel.ITypeDescriptorContext" /> that provides a format context.</param>
        /// <param name="culture">The <see cref="T:System.Globalization.CultureInfo" /> to use as the current culture.</param>
        /// <param name="value">The <see cref="T:System.Object" /> to convert.</param>
        /// <returns>
        /// An <see cref="T:System.Object" /> that represents the converted value.
        /// </returns>
        public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
        {
            // ReSharper disable once ConditionIsAlwaysTrueOrFalse
            if (context == null || context.PropertyDescriptor == null)
            {
                return(Enumerable.Empty <object>());
            }

            var propertyType  = context.PropertyDescriptor.PropertyType;
            var isGenericType = propertyType.IsGenericType;
            var targetType    = isGenericType
                                ? propertyType.GenericTypeArguments.First()
                                : propertyType;

            if (value.IsNullOrEmptyString())
            {
                return(EnumerableInvocations.Empty(targetType));
            }

            // Single IPublishedContent
            IPublishedContent content = value as IPublishedContent;

            if (content != null)
            {
                return(content.As(targetType, null, null, culture));
            }

            // ReSharper disable once PossibleNullReferenceException
            var type = value.GetType();

            // Multiple IPublishedContent
            if (type.IsEnumerableOfType(typeof(IPublishedContent)))
            {
                return(((IEnumerable <IPublishedContent>)value).As(targetType, null, null, null, culture));
            }

            int[] nodeIds = { };

            // First try enumerable strings, ints.
            if (type.IsGenericType || type.IsArray)
            {
                if (type.IsEnumerableOfType(typeof(string)))
                {
                    int n;
                    nodeIds = ((IEnumerable <string>)value)
                              .Select(x => int.TryParse(x, NumberStyles.Any, culture, out n) ? n : -1)
                              .ToArray();
                }

                if (type.IsEnumerableOfType(typeof(int)))
                {
                    nodeIds = ((IEnumerable <int>)value).ToArray();
                }
            }

            // Now csv strings.
            if (!nodeIds.Any())
            {
                var s = value as string ?? value.ToString();
                if (!string.IsNullOrWhiteSpace(s))
                {
                    int n;
                    nodeIds = XmlHelper.CouldItBeXml(s)
                    ? s.GetXmlIds()
                    : s
                              .ToDelimitedList()
                              .Select(x => int.TryParse(x, NumberStyles.Any, culture, out n) ? n : -1)
                              .Where(x => x > 0)
                              .ToArray();
                }
            }

            if (nodeIds.Any())
            {
                var umbracoContext   = UmbracoContext.Current;
                var membershipHelper = new MembershipHelper(umbracoContext);
                var objectType       = UmbracoObjectTypes.Unknown;
                var multiPicker      = new List <IPublishedContent>();

                // Oh so ugly if you let Resharper do this.
                // ReSharper disable once LoopCanBeConvertedToQuery
                foreach (var nodeId in nodeIds)
                {
                    var item = this.GetPublishedContent(nodeId, ref objectType, UmbracoObjectTypes.Document, umbracoContext.ContentCache.GetById)
                               ?? this.GetPublishedContent(nodeId, ref objectType, UmbracoObjectTypes.Media, umbracoContext.MediaCache.GetById)
                               ?? this.GetPublishedContent(nodeId, ref objectType, UmbracoObjectTypes.Member, membershipHelper.GetById);

                    if (item != null)
                    {
                        multiPicker.Add(item);
                    }
                }

                return(multiPicker.As(targetType, null, null, null, culture));
            }

            return(base.ConvertFrom(context, culture, value));
        }