public Task SetValueAsync <T> (IPropertyInfo property, ValueInfo <T> value, PropertyVariation variations = null)
        {
            value = new ValueInfo <T> {
                CustomExpression = value.CustomExpression,
                Source           = value.Source,
                ValueDescriptor  = value.ValueDescriptor,
                SourceDescriptor = value.SourceDescriptor,
                Value            = value.Value
            };

            if (!this.values.TryGetValue(property, out IDictionary <PropertyVariation, object> propertyValues))
            {
                this.values[property] = propertyValues = new Dictionary <PropertyVariation, object> ();
            }

            if (value.Source != ValueSource.Local && ValueEvaluator != null)
            {
                value.Value = (T)ValueEvaluator(property, value.ValueDescriptor, value.SourceDescriptor);
            }
            else if (value.Source == ValueSource.Unset || (property.ValueSources.HasFlag(ValueSources.Default) && Equals(value.Value, default(T))) && value.ValueDescriptor == null && value.SourceDescriptor == null)
            {
                bool changed = false;
                if (variations == NeutralVariations)
                {
                    propertyValues.Remove(NeutralVariations);
                    changed = true;
                }
                else if (variations != null)
                {
                    propertyValues[variations] = value;
                    changed = true;
                }

                if (changed)
                {
                    PropertyChanged?.Invoke(this, new EditorPropertyChangedEventArgs(property, variations));
                    return(Task.CompletedTask);
                }
            }

            object softValue = value;

            if (typeof(T) != property.Type)
            {
                IPropertyConverter converter = property as IPropertyConverter;

                bool changeValueInfo = false;

                object v = value.Value;
                if (ReferenceEquals(value.Value, null) && property.Type.IsValueType)
                {
                    if ((property.ValueSources & ValueSources.Default) == ValueSources.Default)
                    {
                        v = Activator.CreateInstance(property.Type);
                        changeValueInfo = true;
                    }
                }
                else if (converter != null && converter.TryConvert(value.Value, property.Type, out v))
                {
                    changeValueInfo = true;
                }

                if (changeValueInfo)
                {
                    var softType = typeof(ValueInfo <>).MakeGenericType(property.Type);
                    softValue = Activator.CreateInstance(softType);
                    softType.GetProperty("Value").SetValue(softValue, v);
                    softType.GetProperty("ValueDescriptor").SetValue(softValue, value.ValueDescriptor);
                    softType.GetProperty("Source").SetValue(softValue, value.Source);
                    softType.GetProperty("SourceDescriptor").SetValue(softValue, value.SourceDescriptor);
                }

                if (typeof(T).Name == "IReadOnlyList`1")
                {
                    var list = (IReadOnlyList <int>)value.Value;
                    int iv   = 0;
                    foreach (int flag in list)
                    {
                        iv |= flag;
                    }

                    softValue = new ValueInfo <int> {
                        Value  = iv,
                        Source = value.Source
                    };
                }
            }

            // Set to resource won't pass values so we will store it on the info since we just pass it back in GetValue
            if (value.Source == ValueSource.Resource && value.SourceDescriptor is Resource)
            {
                Type rt = value.SourceDescriptor.GetType();
                if (rt.IsGenericType)
                {
                    Type ta = rt.GetGenericArguments()[0];
                    if (typeof(T).IsAssignableFrom(ta))
                    {
                        PropertyInfo pi = rt.GetProperty("Value");
                        value.Value = (T)pi.GetValue(value.SourceDescriptor);
                    }
                    else
                    {
                        TypeConverter converter = TypeDescriptor.GetConverter(ta);
                        if (converter != null && converter.CanConvertTo(typeof(T)))
                        {
                            PropertyInfo pi = rt.GetProperty("Value");
                            value.Value = (T)converter.ConvertTo(pi.GetValue(value.SourceDescriptor), typeof(T));
                        }
                    }
                }
            }

            propertyValues[variations ?? NeutralVariations] = softValue;
            PropertyChanged?.Invoke(this, new EditorPropertyChangedEventArgs(property, variations));
            return(Task.CompletedTask);
        }
        public Task <ValueInfo <T> > GetValueAsync <T> (IPropertyInfo property, PropertyVariation variations = null)
        {
            Type tType = typeof(T);

            IDictionary <PropertyVariation, object> propertyValues;

            if (!this.values.TryGetValue(property, out propertyValues) || !propertyValues.TryGetValue(variations ?? NeutralVariations, out object value))
            {
                return(Task.FromResult(new ValueInfo <T> {
                    Source = (property.ValueSources.HasFlag(ValueSources.Default))
                                                ? ValueSource.Default
                                                : ValueSource.Unset,
                    Value = default(T)
                }));
            }

            var info = value as ValueInfo <T>;

            if (info != null)
            {
                return(Task.FromResult(new ValueInfo <T> {
                    CustomExpression = info.CustomExpression,
                    Source = info.Source,
                    ValueDescriptor = info.ValueDescriptor,
                    SourceDescriptor = info.SourceDescriptor,
                    Value = info.Value
                }));
            }
            else if (value == null || value is T)
            {
                return(Task.FromResult(new ValueInfo <T> {
                    Value = (T)value,
                    Source = ValueSource.Local
                }));
            }
            else if (tType.Name == "IReadOnlyList`1")
            {
                // start with just supporting ints for now
                var predefined = (IReadOnlyDictionary <string, int>)property.GetType().GetProperty(nameof(IHavePredefinedValues <int> .PredefinedValues)).GetValue(property);

                var underlyingInfo = value as ValueInfo <int>;

                int realValue;
                if (value is int i)
                {
                    realValue = i;
                }
                else
                {
                    realValue = ((ValueInfo <int>)value).Value;
                }

                var flags = new List <int> ();
                foreach (int v in predefined.Values)
                {
                    if (v == 0 && realValue != 0)
                    {
                        continue;
                    }

                    if ((realValue & v) == v)
                    {
                        flags.Add(v);
                    }
                }

                return(Task.FromResult((ValueInfo <T>)Convert.ChangeType(new ValueInfo <IReadOnlyList <int> > {
                    Value = flags,
                    Source = underlyingInfo?.Source ?? ValueSource.Local
                }, typeof(ValueInfo <T>))));
            }
            else
            {
                object      sourceDescriptor = null, valueDescriptor = null;
                ValueSource source    = ValueSource.Local;
                Type        valueType = value.GetType();
                if (valueType.IsConstructedGenericType && valueType.GetGenericTypeDefinition() == typeof(ValueInfo <>))
                {
                    source           = (ValueSource)valueType.GetProperty("Source").GetValue(value);
                    sourceDescriptor = valueType.GetProperty(nameof(ValueInfo <T> .SourceDescriptor)).GetValue(value);
                    valueDescriptor  = valueType.GetProperty(nameof(ValueInfo <T> .ValueDescriptor)).GetValue(value);
                    value            = valueType.GetProperty("Value").GetValue(value);
                    valueType        = valueType.GetGenericArguments()[0];
                }

                object             newValue;
                IPropertyConverter converter = property as IPropertyConverter;
                if (converter != null && converter.TryConvert(value, tType, out newValue))
                {
                    return(Task.FromResult(new ValueInfo <T> {
                        Source = source,
                        Value = (T)newValue,
                        ValueDescriptor = valueDescriptor,
                        SourceDescriptor = sourceDescriptor
                    }));
                }
                else if (typeof(T).IsAssignableFrom(valueType))
                {
                    return(Task.FromResult(new ValueInfo <T> {
                        Source = source,
                        Value = (T)value,
                        ValueDescriptor = valueDescriptor,
                        SourceDescriptor = sourceDescriptor
                    }));
                }
            }

            return(Task.FromResult(new ValueInfo <T> {
                Source = (property.ValueSources.HasFlag(ValueSources.Default)) ? ValueSource.Default : ValueSource.Unset,
                Value = default(T)
            }));
        }
Esempio n. 3
0
#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously
        public async Task SetValueAsync <T> (IPropertyInfo property, ValueInfo <T> value, PropertyVariation variation = null)
        {
            if (variation != null)
            {
                throw new NotSupportedException();                 // TODO
            }
            value = new ValueInfo <T> {
                CustomExpression = value.CustomExpression,
                Source           = value.Source,
                ValueDescriptor  = value.ValueDescriptor,
                Value            = value.Value
            };

            if (value.Source != ValueSource.Local && ValueEvaluator != null)
            {
                value.Value = (T)ValueEvaluator(property, value.ValueDescriptor);
            }
            else if (value.Source == ValueSource.Unset || (property.ValueSources.HasFlag(ValueSources.Default) && Equals(value.Value, default(T))) && value.ValueDescriptor == null)
            {
                this.values.Remove(property);
                PropertyChanged?.Invoke(this, new EditorPropertyChangedEventArgs(property));
                return;
            }

            object softValue = value;

            if (typeof(T) != property.Type)
            {
                IPropertyConverter converter = property as IPropertyConverter;

                object v;
                if (converter != null && converter.TryConvert(value.Value, property.Type, out v))
                {
                    var softType = typeof(ValueInfo <>).MakeGenericType(property.Type);
                    softValue = Activator.CreateInstance(softType);
                    softType.GetProperty("Value").SetValue(softValue, v);
                    softType.GetProperty("Source").SetValue(softValue, value.Source);
                }

                if (typeof(T).Name == "IReadOnlyList`1")
                {
                    var list = (IReadOnlyList <int>)value.Value;
                    int iv   = 0;
                    foreach (int flag in list)
                    {
                        iv |= flag;
                    }

                    softValue = new ValueInfo <int> {
                        Value  = iv,
                        Source = value.Source
                    };
                }
            }

            // Set to resource won't pass values so we will store it on the info since we just pass it back in GetValue
            if (value.Source == ValueSource.Resource && value.ValueDescriptor is Resource)
            {
                var rt = value.ValueDescriptor.GetType();
                if (rt.IsGenericType && typeof(T).IsAssignableFrom(rt.GetGenericArguments()[0]))
                {
                    var pi = rt.GetProperty("Value");
                    value.Value = (T)pi.GetValue(value.ValueDescriptor);
                }
            }

            this.values[property] = softValue;
            PropertyChanged?.Invoke(this, new EditorPropertyChangedEventArgs(property));
        }