1 // -----------------------------------------------------------------------
\r
2 // Copyright (c) Microsoft Corporation. All rights reserved.
\r
3 // -----------------------------------------------------------------------
\r
5 using System.Collections.Generic;
\r
6 using System.ComponentModel;
\r
7 using System.ComponentModel.Composition;
\r
9 using System.Reflection;
\r
10 using Microsoft.VisualStudio.TestTools.UnitTesting;
\r
11 using System.ComponentModel.Composition.Hosting;
\r
13 namespace System.ComponentModel.Composition
\r
16 public class DynamicMetadata
\r
19 public void SimpleAttachment()
\r
21 MetadataStore.Container = new CompositionContainer();
\r
22 DynamicMetadataTestClass val = DynamicMetadataTestClass.Get("42");
\r
24 var notYetAttached = TypeDescriptor.GetConverter(val);
\r
25 Assert.IsFalse(notYetAttached.CanConvertFrom(typeof(string)), "The default type converter for DynamicMetadataTestClass shouldn't support round tripping");
\r
27 MetadataStore.AddAttribute(
\r
28 typeof(DynamicMetadataTestClass),
\r
29 ( type, attributes) =>
\r
32 new Attribute[] { new TypeConverterAttribute(typeof(DynamicMetadataTestClassConverter)) }
\r
35 var attached = TypeDescriptor.GetConverter(val);
\r
36 Assert.IsTrue(attached.CanConvertFrom(typeof(string)), "The new type converter for DynamicMetadataTestClass should support round tripping");
\r
40 public void LocalContainer()
\r
42 var container1 = new CompositionContainer();
\r
43 TypeDescriptorServices dat = new TypeDescriptorServices();
\r
44 CompositionBatch batch = new CompositionBatch();
\r
46 container1.Compose(batch);
\r
47 MetadataStore.AddAttribute(
\r
48 typeof(DynamicMetadataTestClass),
\r
49 ( type, attributes) =>
\r
52 new Attribute[] { new TypeConverterAttribute(typeof(DynamicMetadataTestClassConverter)) }
\r
56 DynamicMetadataTestClass val = DynamicMetadataTestClass.Get("42");
\r
58 var notYetAttached = TypeDescriptor.GetConverter(val.GetType());
\r
59 Assert.IsFalse(notYetAttached.CanConvertFrom(typeof(string)), "The default type converter for DynamicMetadataTestClass shouldn't support round tripping");
\r
61 var attached = dat.GetConverter(val.GetType());
\r
62 Assert.IsTrue(attached.CanConvertFrom(typeof(string)), "The new type converter for DynamicMetadataTestClass should support round tripping");
\r
66 public void DualContainers()
\r
68 var container1 = new CompositionContainer();
\r
69 TypeDescriptorServices dat1 = new TypeDescriptorServices();
\r
70 CompositionBatch batch = new CompositionBatch();
\r
71 batch.AddPart(dat1);
\r
72 container1.Compose(batch);
\r
73 MetadataStore.AddAttribute(
\r
74 typeof(DynamicMetadataTestClass),
\r
75 ( type, attributes) =>
\r
78 new Attribute[] { new TypeConverterAttribute(typeof(DynamicMetadataTestClassConverter)) }
\r
84 var container2 = new CompositionContainer();
\r
85 CompositionBatch batch2 = new CompositionBatch();
\r
86 TypeDescriptorServices dat2 = new TypeDescriptorServices();
\r
87 batch2.AddPart(dat2);
\r
88 container2.Compose(batch2);
\r
90 DynamicMetadataTestClass val = DynamicMetadataTestClass.Get("42");
\r
92 var attached1 = dat1.GetConverter(val.GetType());
\r
93 Assert.IsTrue(attached1.CanConvertFrom(typeof(string)), "The new type converter for DynamicMetadataTestClass should support round tripping");
\r
95 var attached2 = dat2.GetConverter(val.GetType());
\r
96 Assert.IsFalse(attached2.CanConvertFrom(typeof(string)), "The default type converter for DynamicMetadataTestClass shouldn't support round tripping");
\r
100 public void ResetContainer()
\r
102 MetadataStore.Container = null;
\r
108 public class TypeDescriptorServices
\r
110 Dictionary<Type, TypeDescriptionProvider> providers = new Dictionary<Type, TypeDescriptionProvider>();
\r
112 internal Dictionary<Type, TypeDescriptionProvider> Providers
\r
114 get { return providers; }
\r
115 set { providers = value; }
\r
118 public ICustomTypeDescriptor GetTypeDescriptor(Type objectType, object instance)
\r
120 if (Providers.ContainsKey(objectType))
\r
122 return Providers[objectType].GetTypeDescriptor(objectType);
\r
129 public void AddProvider(TypeDescriptionProvider provider, Type type)
\r
131 Providers[type] = provider;
\r
133 public TypeConverter GetConverter(Type type)
\r
135 var ictd = GetTypeDescriptor(type, null);
\r
138 return ictd.GetConverter();
\r
142 return TypeDescriptor.GetConverter(type);
\r
147 public static class MetadataStore
\r
149 public static CompositionContainer Container { get; set; }
\r
150 static Dictionary<Type, TypeDescriptionProvider> registeredRedirect = new Dictionary<Type, TypeDescriptionProvider>();
\r
152 public static void AddAttribute(Type target, Func<MemberInfo, IEnumerable<Attribute>, IEnumerable<Attribute>> provider)
\r
154 AddAttribute(target, provider, MetadataStore.Container);
\r
156 public static void AddAttribute(Type target, Func<MemberInfo, IEnumerable<Attribute>, IEnumerable<Attribute>> provider, CompositionContainer container)
\r
158 ContainerUnawareProviderRedirect.GetRedirect(container)[target] = new MetadataStoreProvider(target, provider);
\r
159 RegisterTypeDescriptorInterop(target);
\r
161 private static void RegisterTypeDescriptorInterop(Type target)
\r
163 if (!registeredRedirect.ContainsKey(target))
\r
165 var r = new ContainerUnawareProviderRedirect(target);
\r
166 TypeDescriptor.AddProvider(r, target);
\r
167 registeredRedirect[target] = r;
\r
171 // force a uncache of the information from TypeDescriptor
\r
173 TypeDescriptor.RemoveProvider(registeredRedirect[target], target);
\r
174 TypeDescriptor.AddProvider(registeredRedirect[target], target);
\r
177 public static TypeDescriptorServices GetTypeDescriptorServicesForContainer(CompositionContainer container)
\r
179 if (container != null)
\r
181 var result = container.GetExportedValueOrDefault<TypeDescriptorServices>();
\r
182 if (result == null)
\r
184 var v = new TypeDescriptorServices();
\r
185 CompositionBatch batch = new CompositionBatch();
\r
187 container.Compose(batch);
\r
196 private class ContainerUnawareProviderRedirect : TypeDescriptionProvider
\r
198 public ContainerUnawareProviderRedirect(Type forType)
\r
199 : base(TypeDescriptor.GetProvider(forType))
\r
202 public override ICustomTypeDescriptor GetTypeDescriptor(Type objectType, object instance)
\r
204 var datd = GetTypeDescriptorServicesForContainer(MetadataStore.Container);
\r
205 if (datd == null || !datd.Providers.ContainsKey(objectType))
\r
207 return base.GetTypeDescriptor(objectType, instance);
\r
211 return datd.GetTypeDescriptor(objectType, instance);
\r
215 internal static Dictionary<Type, TypeDescriptionProvider> GetRedirect(CompositionContainer container)
\r
217 TypeDescriptorServices v = GetTypeDescriptorServicesForContainer(container);
\r
218 return v != null ? v.Providers : null;
\r
222 private class MetadataStoreProvider : TypeDescriptionProvider
\r
224 Func<MemberInfo, IEnumerable<Attribute>, IEnumerable<Attribute>> provider;
\r
225 public MetadataStoreProvider(Type forType, Func<MemberInfo, IEnumerable<Attribute>, IEnumerable<Attribute>> provider)
\r
226 : base(TypeDescriptor.GetProvider(forType))
\r
228 this.provider = provider;
\r
230 public override ICustomTypeDescriptor GetTypeDescriptor(Type objectType, object instance)
\r
232 ICustomTypeDescriptor descriptor = base.GetTypeDescriptor(objectType, instance);
\r
233 descriptor = new MetadataStoreTypeDescriptor(objectType, descriptor, provider);
\r
239 private class MetadataStoreTypeDescriptor : CustomTypeDescriptor
\r
242 Func<MemberInfo, IEnumerable<Attribute>, IEnumerable<Attribute>> provider;
\r
243 public MetadataStoreTypeDescriptor(Type targetType, ICustomTypeDescriptor parent, Func<MemberInfo, IEnumerable<Attribute>, IEnumerable<Attribute>> provider)
\r
246 this.targetType = targetType;
\r
247 this.provider = provider;
\r
249 public override TypeConverter GetConverter()
\r
251 TypeConverterAttribute attribute = (TypeConverterAttribute)GetAttributes()[typeof(TypeConverterAttribute)];
\r
252 if (attribute != null)
\r
254 Type c = this.GetTypeFromName(attribute.ConverterTypeName);
\r
255 if ((c != null) && typeof(TypeConverter).IsAssignableFrom(c))
\r
257 return (TypeConverter)Activator.CreateInstance(c);
\r
260 return base.GetConverter();
\r
262 private Type GetTypeFromName(string typeName)
\r
264 if ((typeName == null) || (typeName.Length == 0))
\r
268 int length = typeName.IndexOf(',');
\r
272 type = targetType.Assembly.GetType(typeName);
\r
276 type = Type.GetType(typeName);
\r
278 if ((type == null) && (length != -1))
\r
280 type = Type.GetType(typeName.Substring(0, length));
\r
284 public override AttributeCollection GetAttributes()
\r
286 var n = new List<Attribute>();
\r
287 foreach (var attr in provider(targetType, base.GetAttributes().OfType<Attribute>()))
\r
291 return new AttributeCollection(n.ToArray());
\r
296 public class DynamicMetadataTestClass
\r
300 private DynamicMetadataTestClass(int i)
\r
305 public override string ToString()
\r
307 return i.ToString();
\r
310 public static DynamicMetadataTestClass Get(string s)
\r
312 return new DynamicMetadataTestClass(Int32.Parse(s));
\r
316 public class DynamicMetadataTestClassConverter : TypeConverter
\r
318 public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
\r
320 return sourceType == typeof(string);
\r
322 public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType)
\r
324 return ((DynamicMetadataTestClass)value).ToString();
\r
326 public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
\r
328 return DynamicMetadataTestClass.Get((string)value);
\r
330 public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
\r
332 return destinationType == typeof(string);
\r