Updates referencesource to .NET 4.7
[mono.git] / mcs / class / referencesource / System.Workflow.Activities / Common / BasePropertyDescriptor.cs
1 // Copyright (c) 1999-2002 Microsoft Corporation. All rights reserved. 
2 //  
3 // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, 
4 // WHETHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED 
5 // WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. 
6 // THE ENTIRE RISK OF USE OR RESULTS IN CONNECTION WITH THE USE OF THIS CODE 
7 // AND INFORMATION REMAINS WITH THE USER. 
8 //  
9 using System;
10 using System.ComponentModel;
11 using System.ComponentModel.Design;
12 using System.Collections;
13 using System.Collections.Generic;
14 using System.Resources;
15 using System.Reflection;
16 using System.Globalization;
17 using System.Security;
18 using System.Security.Permissions;
19 using System.Workflow.ComponentModel;
20 using System.Workflow.ComponentModel.Compiler;
21 using System.Workflow.ComponentModel.Design;
22
23 /*********************************************************************
24  * NOTE: A copy of this file exists at: WF\Common\Shared
25  * The two files must be kept in sync.  Any change made here must also
26  * be made to WF\Common\Shared\BasePropertyDescriptor.cs
27 *********************************************************************/
28
29 namespace System.Workflow.Activities.Common
30 {
31     #region Class PropertyDescriptorUtils
32     internal static class PropertyDescriptorUtils
33     {
34         internal static ISite GetSite(IServiceProvider serviceProvider, object component)
35         {
36             ISite site = null;
37
38             if (component != null)
39             {
40                 if ((component is IComponent) && ((IComponent)component).Site != null)
41                     site = ((IComponent)component).Site;
42
43                 if (site == null && component.GetType().IsArray && (component as object[]).Length > 0 && (component as object[])[0] is IComponent)
44                     site = ((IComponent)(component as object[])[0]).Site;
45
46                 if (site == null && serviceProvider != null)
47                 {
48                     IReferenceService referenceService = serviceProvider.GetService(typeof(IReferenceService)) as IReferenceService;
49                     if (referenceService != null)
50                     {
51                         IComponent baseComponent = referenceService.GetComponent(component);
52                         if (baseComponent != null)
53                             site = baseComponent.Site;
54                     }
55                 }
56             }
57
58             if (site == null)
59                 site = serviceProvider as ISite;
60
61             return site;
62         }
63
64         internal static IComponent GetComponent(ITypeDescriptorContext context)
65         {
66             ISite site = (context != null) ? GetSite(context, context.Instance) : null;
67             return (site != null) ? site.Component : null;
68         }
69
70         internal static Type GetBaseType(PropertyDescriptor property, object owner, IServiceProvider serviceProvider)
71         {
72             Type baseType = null;
73
74             Type ownerType = owner.GetType();
75             if (owner != null)
76             {
77                 IDynamicPropertyTypeProvider basetypeProvider = owner as IDynamicPropertyTypeProvider;
78                 if (basetypeProvider != null)
79                     baseType = basetypeProvider.GetPropertyType(serviceProvider, property.Name);
80             }
81
82             if (baseType == null)
83                 baseType = property.PropertyType;
84
85             return baseType;
86         }
87
88         internal static void SetPropertyValue(IServiceProvider serviceProvider, PropertyDescriptor propertyDescriptor, object component, object value)
89         {
90             ComponentChangeDispatcher componentChange = new ComponentChangeDispatcher(serviceProvider, component, propertyDescriptor);
91             try
92             {
93                 propertyDescriptor.SetValue(component, value);
94             }
95             catch (Exception t)
96             {
97                 // If there was a problem setting the controls property then we get:
98                 // ArgumentException (from properties set method)
99                 // ==> Becomes inner exception of TargetInvocationException
100                 // ==> caught here
101                 // Propagate the original exception up
102                 if (t is TargetInvocationException && t.InnerException != null)
103                     throw t.InnerException;
104                 else
105                     throw t;
106             }
107             finally
108             {
109                 componentChange.Dispose();
110             }
111         }
112     }
113     #endregion
114
115     #region Class ComponentChangeDispatcher
116     internal sealed class ComponentChangeDispatcher : IDisposable
117     {
118         private IServiceProvider serviceProvider;
119         private object component;
120         private PropertyDescriptor property;
121         private object oldValue;
122         private object newValue;
123
124         public ComponentChangeDispatcher(IServiceProvider serviceProvider, object component, PropertyDescriptor propertyDescriptor)
125         {
126             this.serviceProvider = serviceProvider;
127             this.component = component;
128             this.property = propertyDescriptor;
129
130             IComponentChangeService changeService = serviceProvider.GetService(typeof(IComponentChangeService)) as IComponentChangeService;
131             if (changeService != null)
132             {
133                 try
134                 {
135                     newValue = oldValue = propertyDescriptor.GetValue(component);
136                     propertyDescriptor.AddValueChanged(component, new EventHandler(OnValueChanged));
137                     changeService.OnComponentChanging(component, propertyDescriptor);
138                 }
139                 catch (CheckoutException coEx)
140                 {
141                     if (coEx == CheckoutException.Canceled)
142                         return;
143                     throw coEx;
144                 }
145             }
146         }
147
148         public void Dispose()
149         {
150             IComponentChangeService changeService = this.serviceProvider.GetService(typeof(IComponentChangeService)) as IComponentChangeService;
151             if (changeService != null)
152                 changeService.OnComponentChanged(this.component, this.property, this.oldValue, this.newValue);
153         }
154
155         private void OnValueChanged(object sender, EventArgs e)
156         {
157             this.newValue = this.property.GetValue(this.component);
158             this.property.RemoveValueChanged(this.component, new EventHandler(OnValueChanged));
159         }
160     }
161     #endregion
162
163     #region Class DynamicPropertyDescriptor
164     internal class DynamicPropertyDescriptor : PropertyDescriptor
165     {
166         private IServiceProvider serviceProvider;
167         private PropertyDescriptor realPropertyDescriptor;
168
169         public DynamicPropertyDescriptor(IServiceProvider serviceProvider, PropertyDescriptor descriptor)
170             : base(descriptor, null)
171         {
172             this.serviceProvider = serviceProvider;
173             this.realPropertyDescriptor = descriptor;
174         }
175
176         public IServiceProvider ServiceProvider
177         {
178             get
179             {
180                 return this.serviceProvider;
181             }
182         }
183
184         public PropertyDescriptor RealPropertyDescriptor
185         {
186             get
187             {
188                 return this.realPropertyDescriptor;
189             }
190         }
191
192         public override string Category
193         {
194             get
195             {
196                 return this.realPropertyDescriptor.Category;
197             }
198         }
199
200         public override AttributeCollection Attributes
201         {
202             get
203             {
204                 ArrayList attributes = new ArrayList();
205                 attributes.AddRange(this.realPropertyDescriptor.Attributes);
206                 attributes.Add(new MergablePropertyAttribute(false));
207                 return new AttributeCollection((Attribute[])attributes.ToArray(typeof(Attribute)));
208             }
209         }
210
211         public override TypeConverter Converter
212         {
213             get
214             {
215                 return this.realPropertyDescriptor.Converter;
216             }
217         }
218
219         public override string Description
220         {
221             get
222             {
223                 return this.realPropertyDescriptor.Description;
224             }
225         }
226
227         public override string DisplayName
228         {
229             get
230             {
231                 return this.realPropertyDescriptor.DisplayName;
232             }
233         }
234
235         public override Type ComponentType
236         {
237             get
238             {
239                 return this.realPropertyDescriptor.ComponentType;
240             }
241         }
242
243         public override Type PropertyType
244         {
245             get
246             {
247                 return this.realPropertyDescriptor.PropertyType;
248             }
249         }
250
251         public override bool IsReadOnly
252         {
253             get
254             {
255                 return this.realPropertyDescriptor.IsReadOnly;
256             }
257         }
258
259         public override void ResetValue(object component)
260         {
261             this.realPropertyDescriptor.ResetValue(component);
262         }
263
264         public override bool CanResetValue(object component)
265         {
266             return this.realPropertyDescriptor.CanResetValue(component);
267         }
268
269         public override bool ShouldSerializeValue(object component)
270         {
271             // work around: The real property descriptor is returning false for all the
272             // SequentialWorkflow class's properties because they all get replaced with 
273             // InheritedPropertyDescriptors on Initialization (in the ComponentDesigner
274             // base class), which is causing problems in the code-only serialization.
275             if (string.Equals(this.realPropertyDescriptor.GetType().FullName, "System.ComponentModel.Design.InheritedPropertyDescriptor", StringComparison.Ordinal))
276                 return true;
277
278             return this.realPropertyDescriptor.ShouldSerializeValue(component);
279         }
280
281         public override object GetValue(object component)
282         {
283             // When a child property is of type event, component could be null.
284             if (component == null)
285                 return null;
286
287             return this.realPropertyDescriptor.GetValue(component);
288         }
289
290         public override void SetValue(object component, object value)
291         {
292             if (component is IComponent)
293                 this.realPropertyDescriptor.SetValue(component, value);
294             else
295                 PropertyDescriptorUtils.SetPropertyValue(ServiceProvider, this.realPropertyDescriptor, component, value);
296         }
297     }
298     #endregion
299
300     #region Class ParameterInfoBasedPropertyDescriptor
301
302     internal class ParameterInfoBasedPropertyDescriptor : PropertyDescriptor
303     {
304         private Type componentType;
305         private string desc = string.Empty;
306         private bool avoidDuplication = false;
307         private object parameter = null; // Could be either ParameterInfo or PropertyInfo
308         private Type parameterType = null;
309         private const string parameterPrefix = "(Parameter) ";
310
311         internal ParameterInfoBasedPropertyDescriptor(Type componentType, ParameterInfo paramInfo, bool avoidDuplication, params Attribute[] attributes)
312             : base((paramInfo.Position == -1) ? "(ReturnValue)" : paramInfo.Name, attributes)
313         {
314             if (componentType == null)
315                 throw new ArgumentNullException("componentType");
316
317             if (paramInfo == null)
318                 throw new ArgumentNullException("paramInfo");
319
320             if (paramInfo.ParameterType == null)
321                 throw new InvalidOperationException(SR.GetString(SR.Error_ParameterTypeResolution, paramInfo.Name));
322
323             this.componentType = componentType;
324             this.parameter = paramInfo;
325             this.avoidDuplication = avoidDuplication;
326             this.parameterType = paramInfo.ParameterType;
327
328             //Build and cache description
329             string qualifier = String.Empty;
330             if ((paramInfo.ParameterType != null) && (paramInfo.ParameterType.IsByRef || (paramInfo.IsIn && paramInfo.IsOut)))
331                 qualifier = SR.GetString(SR.Ref);
332             else if (paramInfo.IsOut || paramInfo.Name == null)
333                 qualifier = SR.GetString(SR.Out);
334             else
335                 qualifier = SR.GetString(SR.In);
336             this.desc = SR.GetString(SR.ParameterDescription, paramInfo.ParameterType.FullName);
337         }
338
339
340         internal ParameterInfoBasedPropertyDescriptor(Type componentType, string propertyName, Type propertyType, bool avoidDuplication, params Attribute[] attributes)
341             : base(propertyName, attributes)
342         {
343             if (componentType == null)
344                 throw new ArgumentNullException("componentType");
345
346             if (propertyType == null)
347                 throw new InvalidOperationException(SR.GetString(SR.Error_ParameterTypeResolution, propertyName));
348
349             this.componentType = componentType;
350             this.parameterType = propertyType;
351             this.avoidDuplication = avoidDuplication;
352             this.desc = SR.GetString(SR.InvokeParameterDescription, propertyType.FullName.ToString());
353         }
354
355         internal Type ParameterType
356         {
357             get
358             {
359                 Type type = this.parameterType;
360                 if (type.IsByRef)
361                     type = type.GetElementType();
362                 return type;
363             }
364         }
365
366         public override string Description
367         {
368             get
369             {
370                 return this.desc;
371             }
372         }
373
374         public override string Category
375         {
376             get
377             {
378                 return SR.GetString(SR.Parameters);
379             }
380         }
381
382         public override object GetEditor(Type editorBaseType)
383         {
384             return TypeDescriptor.GetEditor(PropertyType, editorBaseType);
385         }
386
387         public override string DisplayName
388         {
389             get
390             {
391                 return this.Name;
392             }
393         }
394
395         public override bool IsReadOnly
396         {
397             get
398             {
399                 return false;
400             }
401         }
402
403         public override Type ComponentType
404         {
405             get
406             {
407                 return this.componentType;
408             }
409         }
410
411         public override string Name
412         {
413             get
414             {
415                 if (this.avoidDuplication)
416                 {
417                     // WinOE Bug 10442: should only prefix with "(Parameter)" if there is and existing
418                     // member of the same name.
419                     return GetParameterPropertyName(this.componentType, base.Name);
420                 }
421                 else
422                     return base.Name;
423             }
424         }
425
426         internal static MemberInfo FindMatchingMember(string name, Type ownerType, bool ignoreCase)
427         {
428             MemberInfo matchingMember = null;
429             foreach (MemberInfo memberInfo in ownerType.GetMembers(BindingFlags.FlattenHierarchy | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic))
430             {
431                 if (memberInfo.Name.Equals(name, ((ignoreCase) ? StringComparison.CurrentCultureIgnoreCase : StringComparison.CurrentCulture)))
432                 {
433                     matchingMember = memberInfo;
434                     break;
435                 }
436             }
437             return matchingMember;
438         }
439
440         public override Type PropertyType
441         {
442             get
443             {
444                 Type propertyType = ParameterType;
445                 if (propertyType == null)
446                     propertyType = typeof(ActivityBind);
447                 return propertyType;
448             }
449         }
450
451         public override TypeConverter Converter
452         {
453             get
454             {
455                 //We return this to make sure that we can bind parameters through UI
456                 return new ActivityBindTypeConverter();
457             }
458         }
459
460         public override AttributeCollection Attributes
461         {
462             get
463             {
464                 ArrayList attributes = new ArrayList();
465                 attributes.AddRange(base.Attributes);
466                 attributes.AddRange(TypeDescriptor.GetAttributes(PropertyType));
467                 return new AttributeCollection((Attribute[])attributes.ToArray(typeof(Attribute)));
468             }
469         }
470
471         public override void ResetValue(object component)
472         {
473             if (PropertyType != null && !PropertyType.IsValueType)
474                 SetValue(component, null);
475         }
476
477         public override bool CanResetValue(object component)
478         {
479             return false;
480         }
481
482         public override bool ShouldSerializeValue(object component)
483         {
484             return false;
485         }
486
487         public override void SetValue(object component, object value)
488         {
489             // the logic for notifications is borrowed from ReflectPropertyDescritpor
490             if (component == null)
491                 return;
492
493             IServiceProvider serviceProvider = GetSite(component);
494             ComponentChangeDispatcher componentChange = (serviceProvider != null) ? new ComponentChangeDispatcher(serviceProvider, component, this) : null;
495
496             try
497             {
498                 WorkflowParameterBindingCollection parameters = GetParameterBindings(component);
499                 if (parameters != null)
500                 {
501                     string propertyName = String.Empty;
502                     if (this.Name.StartsWith(parameterPrefix, StringComparison.Ordinal))
503                         propertyName = this.Name.Substring(parameterPrefix.Length);
504                     else
505                         propertyName = this.Name;
506
507                     WorkflowParameterBinding binding = null;
508                     if (parameters.Contains(propertyName))
509                         binding = parameters[propertyName];
510                     else
511                     {
512                         binding = new WorkflowParameterBinding(propertyName);
513                         parameters.Add(binding);
514                     }
515
516                     if (value is ActivityBind)
517                         binding.SetBinding(WorkflowParameterBinding.ValueProperty, value as ActivityBind);
518                     else
519                         binding.SetValue(WorkflowParameterBinding.ValueProperty, value);
520
521                     OnValueChanged(component, EventArgs.Empty);
522                 }
523             }
524             catch (Exception t)
525             {
526                 // If there was a problem setting the controls property then we get:
527                 // ArgumentException (from properties set method)
528                 // ==> Becomes inner exception of TargetInvocationException
529                 // ==> caught here
530                 // Propagate the original exception up
531                 if (t is TargetInvocationException && t.InnerException != null)
532                     throw t.InnerException;
533                 else
534                     throw t;
535             }
536             finally
537             {
538                 // Now notify the change service that the change was successful.
539                 if (componentChange != null)
540                     componentChange.Dispose();
541             }
542         }
543
544         public override object GetValue(object component)
545         {
546             WorkflowParameterBindingCollection parameters = GetParameterBindings(component);
547             string displayName = this.Name;
548             string propertyName = (displayName.StartsWith(parameterPrefix, StringComparison.Ordinal)) ? displayName.Substring(parameterPrefix.Length) : displayName;
549             if (parameters != null && parameters.Contains(propertyName))
550             {
551                 if (parameters[propertyName].IsBindingSet(WorkflowParameterBinding.ValueProperty))
552                     return parameters[propertyName].GetBinding(WorkflowParameterBinding.ValueProperty);
553                 else
554                     return parameters[propertyName].GetValue(WorkflowParameterBinding.ValueProperty);
555             }
556
557             return null;
558         }
559
560         private WorkflowParameterBindingCollection GetParameterBindings(object component)
561         {
562             WorkflowParameterBindingCollection retVal = null;
563             MemberInfo memberInfo = component.GetType().GetProperty("ParameterBindings", BindingFlags.GetProperty | BindingFlags.Public | BindingFlags.Instance | BindingFlags.FlattenHierarchy | BindingFlags.ExactBinding, null, typeof(WorkflowParameterBindingCollection), new Type[] { }, new ParameterModifier[] { });
564             if (memberInfo != null)
565                 retVal = component.GetType().InvokeMember("ParameterBindings", BindingFlags.GetProperty | BindingFlags.Public | BindingFlags.Instance | BindingFlags.FlattenHierarchy | BindingFlags.ExactBinding, null, component, new object[] { }, CultureInfo.InvariantCulture) as WorkflowParameterBindingCollection;
566             return retVal;
567         }
568
569         public static string GetParameterPropertyName(Type componentType, string paramName)
570         {
571             string paramPropertyName = paramName;
572             if (FindMatchingMember(paramName, componentType, false) != null)
573                 paramPropertyName = parameterPrefix + paramName;
574
575             return paramPropertyName;
576         }
577     }
578     #endregion
579
580     #region IPropertyValueProvider Interface
581     internal interface IPropertyValueProvider
582     {
583         ICollection GetPropertyValues(ITypeDescriptorContext typeDescriptorContext);
584     }
585     #endregion
586
587     #region Class PropertyValueProviderTypeConverter
588     internal class PropertyValueProviderTypeConverter : TypeConverter
589     {
590         public PropertyValueProviderTypeConverter()
591         {
592         }
593
594         public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
595         {
596             // grab all property values
597             IPropertyValueProvider valuesProvider = null;
598             object[] instances = context.Instance as object[];
599             if (instances != null && instances.Length > 0)
600                 valuesProvider = instances[0] as IPropertyValueProvider;
601             else
602                 valuesProvider = context.Instance as IPropertyValueProvider;
603
604             ICollection values = new object[] { };
605             if (valuesProvider != null)
606                 values = valuesProvider.GetPropertyValues(context);
607
608             return new StandardValuesCollection(values);
609         }
610
611         public override bool GetStandardValuesSupported(ITypeDescriptorContext context)
612         {
613             return true;
614         }
615
616         public override bool GetStandardValuesExclusive(ITypeDescriptorContext context)
617         {
618             return true;
619         }
620     }
621     #endregion
622
623     #region Class TypePropertyDescriptor
624     internal class TypePropertyDescriptor : DynamicPropertyDescriptor
625     {
626         public TypePropertyDescriptor(IServiceProvider serviceProvider, PropertyDescriptor actualPropDesc)
627             : base(serviceProvider, actualPropDesc)
628         {
629         }
630
631         public override TypeConverter Converter
632         {
633             get
634             {
635                 // work around: a direct type comparison would not work because the types in this file are compiled
636                 // into the component model and the activities dll separately.  The assembly name differs thus
637                 // the comparison fails.  Work around by getting the type from the same assembly before doing
638                 // the comparison.
639                 TypeConverter baseTypeConverter = base.Converter;
640                 string baseConverterTypeName = baseTypeConverter.GetType().FullName;
641                 Type baseConverterType = Assembly.GetExecutingAssembly().GetType(baseConverterTypeName);
642                 if (baseConverterType != null && typeof(TypePropertyTypeConverter).IsAssignableFrom(baseConverterType))
643                     return baseTypeConverter;
644                 else
645                     return new TypePropertyTypeConverter();
646             }
647         }
648
649         public override object GetValue(object component)
650         {
651             if (component == null)
652                 throw new ArgumentNullException("component");
653
654             object value = base.GetValue(component);
655
656             if (value == null)
657             {
658                 // See if there is a value in the user data DesignTimeTypeNames hashtable. 
659                 // If yes, it's probably a wrong type name.  Show the name anyway.
660                 DependencyObject dependencyObject = component as DependencyObject;
661                 if (dependencyObject != null)
662                 {
663                     object key = DependencyProperty.FromName(this.RealPropertyDescriptor.Name, this.RealPropertyDescriptor.ComponentType);
664                     value = Helpers.GetDesignTimeTypeName(dependencyObject, key);
665                     if (string.IsNullOrEmpty(value as string))
666                     {
667                         key = this.RealPropertyDescriptor.ComponentType.FullName + "." + this.RealPropertyDescriptor.Name;
668                         value = Helpers.GetDesignTimeTypeName(dependencyObject, key);
669                     }
670                 }
671             }
672
673             return value;
674         }
675
676         public override void SetValue(object component, object value)
677         {
678             if (component == null)
679                 throw new ArgumentNullException("component");
680
681             if (value != null)
682             {
683                 Type type = value as Type;
684                 ITypeFilterProvider filterProvider = PropertyDescriptorUtils.GetComponent(new TypeDescriptorContext(ServiceProvider, RealPropertyDescriptor, component)) as ITypeFilterProvider;
685                 if (filterProvider != null)
686                     filterProvider.CanFilterType(type, true); //this will throw an exception if the type is not correctly filterable
687             }
688
689             base.SetValue(component, value);
690         }
691     }
692     #endregion
693
694     #region Class TypePropertyValueProviderTypeConverter
695     internal class TypePropertyValueProviderTypeConverter : TypePropertyTypeConverter
696     {
697         // NOTE: Copied from PropertyValueProviderTypeConverter.
698         // The purpose of this type converter is so that we can both provide standard values and
699         // convert System.Type to string.
700         public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
701         {
702             // grab all property values
703             IPropertyValueProvider valuesProvider = null;
704             object[] instances = context.Instance as object[];
705             if (instances != null && instances.Length > 0)
706                 valuesProvider = instances[0] as IPropertyValueProvider;
707             else
708                 valuesProvider = context.Instance as IPropertyValueProvider;
709
710             ICollection values = new object[] { };
711             if (valuesProvider != null && context != null)
712                 values = valuesProvider.GetPropertyValues(context);
713
714             return new StandardValuesCollection(values);
715         }
716         public override bool GetStandardValuesSupported(ITypeDescriptorContext context)
717         {
718             return true;
719         }
720         public override bool GetStandardValuesExclusive(ITypeDescriptorContext context)
721         {
722             return true;
723         }
724     }
725     #endregion
726
727     #region Class TypePropertyTypeConverter
728     internal class TypePropertyTypeConverter : TypeConverter
729     {
730         public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
731         {
732             if (sourceType == null)
733                 throw new ArgumentNullException("sourceType");
734
735             if (TypeDescriptor.Equals(sourceType, typeof(string)))
736                 return true;
737
738             return base.CanConvertFrom(context, sourceType);
739
740         }
741
742         public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
743         {
744             if (destinationType == null)
745                 throw new ArgumentNullException("destinationType");
746
747             if (TypeDescriptor.Equals(destinationType, typeof(Type)))
748                 return true;
749
750             return base.CanConvertTo(context, destinationType);
751         }
752
753         public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object valueToConvert)
754         {
755             string typeName = valueToConvert as string;
756             if (String.IsNullOrEmpty(typeName))
757                 return null;
758
759             if (context != null)
760             {
761                 ITypeProvider typeProvider = context.GetService(typeof(ITypeProvider)) as ITypeProvider;
762                 if (typeProvider != null)
763                     return typeProvider.GetType(typeName, true);
764             }
765
766             return base.ConvertFrom(context, culture, valueToConvert);
767         }
768
769         public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
770         {
771             if (value is Type && TypeDescriptor.Equals(destinationType, typeof(string)))
772                 return ((Type)value).FullName;
773
774             return base.ConvertTo(context, culture, value, destinationType);
775         }
776     }
777     #endregion
778 }