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) })); }
#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)); }