File: AuthoringOM\Design\PropertyDescriptors.cs
Project: ndp\cdf\src\WF\Common\System.Workflow.ComponentModel.csproj (System.Workflow.ComponentModel)
namespace System.Workflow.ComponentModel.Design
{
    #region Imports
 
    using System;
    using System.IO;
    using System.ComponentModel;
    using System.ComponentModel.Design;
    using System.Collections;
    using System.Collections.Generic;
    using System.Reflection;
    using System.CodeDom;
    using System.Windows.Forms;
    using System.Windows.Forms.Design;
    using System.Workflow.ComponentModel.Compiler;
    using System.Workflow.ComponentModel.Serialization;
 
    using System.Drawing.Design;
    using System.Collections.Specialized;
    using System.Diagnostics;
    using System.Globalization;
 
    #endregion
 
    #region Class IDPropertyDescriptor
    internal sealed class IDPropertyDescriptor : DynamicPropertyDescriptor
    {
        internal IDPropertyDescriptor(IServiceProvider serviceProvider, PropertyDescriptor actualPropDesc)
            : base(serviceProvider, actualPropDesc)
        {
        }
 
        public override bool CanResetValue(object component)
        {
            return false;
        }
 
        public override void SetValue(object component, object value)
        {
            Activity activity = component as Activity;
            if (activity != null)
            {
                ISite site = PropertyDescriptorUtils.GetSite(ServiceProvider, component);
                if (site == null)
                    throw new Exception(SR.GetString(SR.General_MissingService, typeof(ISite).FullName));
 
                IIdentifierCreationService identifierCreationService = site.GetService(typeof(IIdentifierCreationService)) as IIdentifierCreationService;
                if (identifierCreationService == null)
                    throw new Exception(SR.GetString(SR.General_MissingService, typeof(IIdentifierCreationService).FullName));
 
                string newID = value as string;
                identifierCreationService.ValidateIdentifier(activity, newID);
 
                DesignerHelpers.UpdateSiteName(activity, newID);
                base.SetValue(component, value);
            }
        }
    }
    #endregion
 
    #region Class NamePropertyDescriptor
    internal sealed class NamePropertyDescriptor : DynamicPropertyDescriptor
    {
        internal NamePropertyDescriptor(IServiceProvider serviceProvider, PropertyDescriptor actualPropDesc)
            : base(serviceProvider, actualPropDesc)
        {
        }
 
        public override string Category
        {
            get
            {
                return SR.GetString(SR.Activity);
            }
        }
 
        public override string Description
        {
            get
            {
                return SR.GetString(SR.RootActivityNameDesc);
            }
        }
 
        public override void SetValue(object component, object value)
        {
            Activity activity = component as Activity;
            if (activity != null)
            {
                // validate the identifier
                IIdentifierCreationService identifierCreationService = activity.Site.GetService(typeof(IIdentifierCreationService)) as IIdentifierCreationService;
                if (identifierCreationService == null)
                    throw new Exception(SR.GetString(SR.General_MissingService, typeof(IIdentifierCreationService).FullName));
 
                string name = value as string;
                identifierCreationService.ValidateIdentifier(activity, name);
 
                bool isVB = (CompilerHelpers.GetSupportedLanguage(activity.Site) == SupportedLanguages.VB);
                Type designedType = Helpers.GetDataSourceClass(Helpers.GetRootActivity(activity), activity.Site);
                if (designedType != null)
                {
                    MemberInfo matchingMember = ActivityBindPropertyDescriptor.FindMatchingMember(name, designedType, isVB);
                    if (matchingMember != null)
                        throw new ArgumentException(SR.GetString(SR.Error_ActivityNameExist, name));
                }
                IMemberCreationService memberCreationService = activity.Site.GetService(typeof(IMemberCreationService)) as IMemberCreationService;
                if (memberCreationService == null)
                    throw new InvalidOperationException(SR.GetString(SR.General_MissingService, typeof(IMemberCreationService).FullName));
 
                IDesignerHost host = activity.Site.GetService(typeof(IDesignerHost)) as IDesignerHost;
                if (host == null)
                    throw new InvalidOperationException(SR.GetString(SR.General_MissingService, typeof(IDesignerHost).FullName));
 
                // We need to update the activityType's name before trying to update the type because
                // updating the type causes a flush, which access the custom activity's properties, and 
                // doing so requires the new type name
                string newClassName = name;
                int indexOfDot = host.RootComponentClassName.LastIndexOf('.');
                if (indexOfDot > 0)
                    newClassName = host.RootComponentClassName.Substring(0, indexOfDot + 1) + name;
 
                // IMPORTANT: You must update the class name in code before renaming the site, since
                // VS's OnComponentRename updates the RootComponentClassName, so the flush code called
                // in our OnComponentRename tries to access the new class for information.
                memberCreationService.UpdateTypeName(((Activity)host.RootComponent).GetValue(WorkflowMarkupSerializer.XClassProperty) as string, newClassName);
 
                //((Activity)host.RootComponent).Name = name;
                ((Activity)host.RootComponent).SetValue(WorkflowMarkupSerializer.XClassProperty, newClassName);
                base.SetValue(component, value);
 
                // Update the site name so the component name shows up correctly in the designer
                DesignerHelpers.UpdateSiteName((Activity)host.RootComponent, name);
            }
        }
 
        public override bool CanResetValue(object component)
        {
            return false;
        }
    }
    #endregion
 
    #region Class PropertyDescriptorUtils
    internal static class PropertyDescriptorFilter
    {
        internal static PropertyDescriptorCollection FilterProperties(IServiceProvider serviceProvider, object propertyOwner, PropertyDescriptorCollection props)
        {
            Hashtable properties = new Hashtable();
            foreach (PropertyDescriptor prop in props)
            {
                if (!properties.ContainsKey(prop.Name))
                    properties.Add(prop.Name, prop);
            }
 
            FilterProperties(serviceProvider, propertyOwner, properties);
 
            PropertyDescriptor[] returnProps = new PropertyDescriptor[properties.Count];
            properties.Values.CopyTo(returnProps, 0);
            return new PropertyDescriptorCollection(returnProps);
        }
 
        internal static void FilterProperties(IServiceProvider serviceProvider, object propertyOwner, IDictionary props)
        {
            InternalFilterProperties(serviceProvider, propertyOwner, props);
 
            if (propertyOwner != null)
            {
                foreach (PropertyDescriptor property in GetPropertiesForEvents(serviceProvider, propertyOwner))
                {
                    if (!props.Contains(property.Name))
                        props.Add(property.Name, property);
                }
            }
        }
 
        private static void InternalFilterProperties(IServiceProvider serviceProvider, object propertyOwner, IDictionary properties)
        {
            // change property descriptors
            Hashtable newProperties = new Hashtable();
            foreach (object key in properties.Keys)
            {
                PropertyDescriptor propDesc = properties[key] as PropertyDescriptor;
                if (string.Equals(propDesc.Name, "Name", StringComparison.Ordinal) && typeof(Activity).IsAssignableFrom(propDesc.ComponentType))
                {
                    //Activity id
                    Activity activity = propertyOwner as Activity;
                    if (activity != null && activity == Helpers.GetRootActivity(activity))
                        newProperties[key] = new NamePropertyDescriptor(serviceProvider, propDesc);
                    else
                        newProperties[key] = new IDPropertyDescriptor(serviceProvider, propDesc);
                }
                else if (!(propDesc is ActivityBindPropertyDescriptor) && ActivityBindPropertyDescriptor.IsBindableProperty(propDesc))
                {
                    if (typeof(Type).IsAssignableFrom(propDesc.PropertyType) && !(propDesc is ParameterInfoBasedPropertyDescriptor))
                        propDesc = new TypePropertyDescriptor(serviceProvider, propDesc);
                    newProperties[key] = new ActivityBindPropertyDescriptor(serviceProvider, propDesc, propertyOwner);
                }
                else if (typeof(Type).IsAssignableFrom(propDesc.PropertyType))
                {
                    newProperties[key] = new TypePropertyDescriptor(serviceProvider, propDesc);
                }
                else
                {
                    newProperties[key] = new DynamicPropertyDescriptor(serviceProvider, propDesc);
                }
            }
 
            foreach (object key in newProperties.Keys)
            {
                properties[key] = newProperties[key];
            }
        }
 
        internal static PropertyDescriptorCollection GetPropertiesForEvents(IServiceProvider serviceProvider, object eventOwner)
        {
            //Now for each event we need to add properties
            List<PropertyDescriptor> properties = new List<PropertyDescriptor>();
 
            // Find out if there is a data context.
            IEventBindingService eventBindingService = serviceProvider.GetService(typeof(IEventBindingService)) as IEventBindingService;
            if (eventBindingService != null)
            {
                foreach (EventDescriptor eventDesc in TypeDescriptor.GetEvents(eventOwner))
                {
                    if (eventDesc.IsBrowsable)
                    {
                        PropertyDescriptor propertyDescriptor = eventBindingService.GetEventProperty(eventDesc);
                        if (!(propertyDescriptor is ActivityBindPropertyDescriptor) && ActivityBindPropertyDescriptor.IsBindableProperty(propertyDescriptor))
                            properties.Add(new ActivityBindPropertyDescriptor(serviceProvider, propertyDescriptor, eventOwner));
                        else
                            properties.Add(propertyDescriptor);
                    }
                }
            }
 
            return new PropertyDescriptorCollection(properties.ToArray());
        }
    }
    #endregion
 
    #region ActivityBind PropertyBrowser Integration
 
    #region Class ActivityBindPropertyDescriptor
    /// Please note that ActivityBindPropertyDescriptor is now changed so that it can support MetaProperty binds too.
    /// Although this feature is not yet enabled. Please change code in the PropertyDescritorUtils.InternalFilterProperties to support it
 
    /// We need this property descriptor for following reason:
    /// When we are not in data context we support emission of events directly by using EventBindingService
    /// When we do this the events dont get stored in the DependencyObject rather than we store them in userdata
    /// Only the event property descriptor knows how to get it back.
    /// At the same time we also support Promotion of the events (ActivityBind) when using this the information gets
    /// stored directly in the DependencyObject which we fetch from the ActivityBindPropertyDescriptor base class
 
    /// Whenever the code in this class is changed please run the following test cases
    /// 1. In ActivityDesigner Drop Code and Promote Properties. (ExecuteCode should get promoted)
    /// 2. In ActivityDesigner, change the promoted property to event handler (Event needs to be emitted with += syntax)
    /// 3. In ActivityDesigner, Set the data context to true and try to generate the event for code. (Event should be emitted in DataContext)
    /// 4. In ActivityDesigner, make sure that when within data context the serialization works through the bind, when outside works through +=
    /// Try all of the above cases in WorkflowDesigner where root supports datacontext, roots that dont support data context
    internal class ActivityBindPropertyDescriptor : DynamicPropertyDescriptor
    {
        private object propertyOwner = null;
 
        internal ActivityBindPropertyDescriptor(IServiceProvider serviceProvider, PropertyDescriptor realPropertyDescriptor, object propertyOwner)
            : base(serviceProvider, realPropertyDescriptor)
        {
            this.propertyOwner = propertyOwner;
        }
 
        public override bool IsReadOnly
        {
            get
            {
                return RealPropertyDescriptor.IsReadOnly;
            }
        }
 
        public override TypeConverter Converter
        {
            get
            {
                TypeConverter baseTypeConverter = base.Converter;
                if (typeof(ActivityBindTypeConverter).IsAssignableFrom(baseTypeConverter.GetType()))
                    return baseTypeConverter;
                else
                    return new ActivityBindTypeConverter();
            }
        }
 
        public override AttributeCollection Attributes
        {
            get
            {
                List<Attribute> attributes = new List<Attribute>();
                foreach (Attribute attribute in base.Attributes)
                    attributes.Add(attribute);
 
                object uiTypeEditor = RealPropertyDescriptor.GetEditor(typeof(UITypeEditor));
                object value = (PropertyOwner != null) ? GetValue(PropertyOwner) : null;
                bool propertiesSupported = RealPropertyDescriptor.Converter.GetPropertiesSupported((PropertyOwner != null) ? new TypeDescriptorContext(ServiceProvider, RealPropertyDescriptor, PropertyOwner) : null);
                if (((uiTypeEditor == null && !propertiesSupported) || value is ActivityBind) && !IsReadOnly)
                    attributes.Add(new EditorAttribute(typeof(BindUITypeEditor), typeof(UITypeEditor)));
 
                return new AttributeCollection(attributes.ToArray());
            }
        }
 
        public override object GetEditor(Type editorBaseType)
        {
            //If the converter is simple type converter and there is a simple UITypeEditor
            object editor = base.GetEditor(editorBaseType);
            if (editorBaseType == typeof(UITypeEditor) && !IsReadOnly)
            {
                object value = (PropertyOwner != null) ? GetValue(PropertyOwner) : null;
                bool propertiesSupported = RealPropertyDescriptor.Converter.GetPropertiesSupported((PropertyOwner != null) ? new TypeDescriptorContext(ServiceProvider, RealPropertyDescriptor, PropertyOwner) : null);
                if (value is ActivityBind || (editor == null && !propertiesSupported))
                    editor = new BindUITypeEditor();
            }
            return editor;
        }
 
        public override object GetValue(object component)
        {
            object value = null;
 
            DependencyObject dependencyObj = component as DependencyObject;
            DependencyProperty dependencyProperty = DependencyProperty.FromName(Name, ComponentType);
            if (dependencyObj != null && dependencyProperty != null)
            {
                if (dependencyObj.IsBindingSet(dependencyProperty))
                    value = dependencyObj.GetBinding(dependencyProperty);
            }
 
            //We have to also call base's getvalue as Bindings are stored in MetaProperties collection of DependencyObject but
            //actual values are stored in DependencyValueProperties
            if (!(value is ActivityBind))
                value = base.GetValue(component);
 
            return value;
        }
 
        public override void SetValue(object component, object value)
        {
            object oldValue = GetValue(component);
 
            ActivityBind activityBind = value as ActivityBind;
 
            DependencyObject dependencyObj = component as DependencyObject;
            DependencyProperty dependencyProperty = DependencyProperty.FromName(Name, ComponentType);
            if (dependencyObj != null && dependencyProperty != null && activityBind != null)
            {
                ComponentChangeDispatcher componentChangeDispatcher = new ComponentChangeDispatcher(ServiceProvider, dependencyObj, this);
                try
                {
                    if (dependencyProperty.IsEvent && ServiceProvider != null)
                    {
                        IEventBindingService eventBindingService = ServiceProvider.GetService(typeof(IEventBindingService)) as IEventBindingService;
                        if (eventBindingService != null)
                        {
                            EventDescriptor eventDescriptor = eventBindingService.GetEvent(RealPropertyDescriptor);
                            if (eventDescriptor != null)
                                RealPropertyDescriptor.SetValue(component, null);
                        }
                    }
 
                    dependencyObj.SetBinding(dependencyProperty, activityBind);
                    base.OnValueChanged(dependencyObj, EventArgs.Empty);
                }
                finally
                {
                    componentChangeDispatcher.Dispose();
                }
            }
            else
            {
                if (dependencyObj != null && dependencyProperty != null && dependencyObj.IsBindingSet(dependencyProperty))
                {
                    ComponentChangeDispatcher componentChangeDispatcher = new ComponentChangeDispatcher(ServiceProvider, dependencyObj, this);
                    try
                    {
                        dependencyObj.RemoveProperty(dependencyProperty);
                        // Need to fire component changed event because this means we're clearing
                        // out a previously set Bind value.  If the new value matches the old value stored in the user data, 
                        // base.SetValue will do nothing but return.  When that happens, if we don't fire a change
                        // event here, we'll still have the activity bind in the code or xoml file.
                        base.OnValueChanged(dependencyObj, EventArgs.Empty);
                    }
                    finally
                    {
                        componentChangeDispatcher.Dispose();
                    }
                }
 
                base.SetValue(component, value);
            }
 
            //Following code is for making sure that when we change the value from activity bind to actual value
            //and from actual value to activity bind; we need to change the UITypeEditor associated with property
            //from data binding editor to the editor specified by the user
            if (oldValue != value &&
                ((oldValue is ActivityBind && !(value is ActivityBind)) ||
                 (!(oldValue is ActivityBind) && value is ActivityBind)))
            {
                TypeDescriptor.Refresh(component);
            }
        }
 
        #region Helpers
        internal object PropertyOwner
        {
            get
            {
                return this.propertyOwner;
            }
        }
        #endregion
 
        #region Static Helpers
        internal static IList<MemberInfo> GetBindableMembers(object obj, ITypeDescriptorContext context)
        {
            List<MemberInfo> memberInfos = new List<MemberInfo>();
 
            IDesignerHost designerHost = context.GetService(typeof(IDesignerHost)) as IDesignerHost;
            Activity rootActivity = (designerHost != null) ? designerHost.RootComponent as Activity : null;
            Type objectType = (obj == rootActivity) ? Helpers.GetDataSourceClass(rootActivity, context) : obj.GetType();
 
            Type memberType = PropertyDescriptorUtils.GetBaseType(context.PropertyDescriptor, context.Instance, context);
 
            if (objectType != null && memberType != null)
            {
                DependencyProperty dependencyProperty = DependencyProperty.FromName(context.PropertyDescriptor.Name, context.PropertyDescriptor.ComponentType);
                bool includeEvents = (dependencyProperty != null && dependencyProperty.IsEvent);
 
                BindingFlags bindingFlags = BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.FlattenHierarchy;
                if (obj == rootActivity)
                    bindingFlags |= BindingFlags.NonPublic;
 
                foreach (MemberInfo memberInfo in objectType.GetMembers(bindingFlags))
                {
                    //filter our methods with System.Diagnostics.DebuggerNonUserCodeAttribute
                    object[] nonUserCodeAttributes = memberInfo.GetCustomAttributes(typeof(System.Diagnostics.DebuggerNonUserCodeAttribute), false);
                    if (nonUserCodeAttributes != null && nonUserCodeAttributes.Length > 0 && nonUserCodeAttributes[0] is System.Diagnostics.DebuggerNonUserCodeAttribute)
                        continue;
 
                    object[] browsableAttributes = memberInfo.GetCustomAttributes(typeof(BrowsableAttribute), false);
                    if (browsableAttributes.Length > 0)
                    {
                        bool browsable = false;
 
                        BrowsableAttribute browsableAttribute = browsableAttributes[0] as BrowsableAttribute;
                        if (browsableAttribute != null)
                        {
                            browsable = browsableAttribute.Browsable;
                        }
                        else
                        {
                            try
                            {
                                AttributeInfoAttribute attributeInfoAttribute = browsableAttributes[0] as AttributeInfoAttribute;
                                if (attributeInfoAttribute != null && attributeInfoAttribute.AttributeInfo.ArgumentValues.Count > 0)
                                    browsable = (bool)attributeInfoAttribute.AttributeInfo.GetArgumentValueAs(context, 0, typeof(bool));
                            }
                            catch
                            {
                            }
                        }
 
                        if (!browsable)
                            continue;
                    }
 
                    if (memberInfo.DeclaringType == typeof(System.Object) && (string.Equals(memberInfo.Name, "Equals", StringComparison.Ordinal) || string.Equals(memberInfo.Name, "ReferenceEquals", StringComparison.Ordinal)))
                        continue;
 
                    bool addMember = false;
                    bool isProtectedOrPublicMember = false;
                    bool isInternalMember = false;
                    if (includeEvents && memberInfo is EventInfo)
                    {
                        EventInfo eventInfo = memberInfo as EventInfo;
 
                        MethodInfo addAccessor = eventInfo.GetAddMethod();
                        MethodInfo removeAccessor = eventInfo.GetRemoveMethod();
 
                        isProtectedOrPublicMember = ((addAccessor != null && addAccessor.IsFamily) || (removeAccessor != null && removeAccessor.IsFamily) ||
                                                    (addAccessor != null && addAccessor.IsPublic) || (removeAccessor != null && removeAccessor.IsPublic));
                        isInternalMember = ((addAccessor != null && addAccessor.IsAssembly) || (removeAccessor != null && removeAccessor.IsAssembly));
 
                        addMember = TypeProvider.IsAssignable(memberType, eventInfo.EventHandlerType);
                    }
                    else if (memberInfo is FieldInfo)
                    {
                        FieldInfo fieldInfo = memberInfo as FieldInfo;
                        isProtectedOrPublicMember = (fieldInfo.IsFamily || fieldInfo.IsPublic);
                        isInternalMember = fieldInfo.IsAssembly;
                        addMember = TypeProvider.IsAssignable(memberType, fieldInfo.FieldType);
                    }
                    else if (memberInfo is PropertyInfo)
                    {
                        PropertyInfo propertyInfo = memberInfo as PropertyInfo;
 
                        MethodInfo getAccessor = propertyInfo.GetGetMethod();
                        MethodInfo setAccessor = propertyInfo.GetSetMethod();
 
                        isProtectedOrPublicMember = ((getAccessor != null && getAccessor.IsFamily) || (setAccessor != null && setAccessor.IsFamily) ||
                                                    (getAccessor != null && getAccessor.IsPublic) || (setAccessor != null && setAccessor.IsPublic));
                        isInternalMember = ((getAccessor != null && getAccessor.IsAssembly) || (setAccessor != null && setAccessor.IsAssembly));
                        addMember = (getAccessor != null && TypeProvider.IsAssignable(memberType, propertyInfo.PropertyType));
                    }
 
                    //We only want to allow binding to protected, public and internal members of baseType
                    if (memberInfo.DeclaringType != objectType && !isProtectedOrPublicMember && !(memberInfo.DeclaringType.Assembly == null && isInternalMember))
                        addMember = false;
 
                    if (addMember)
                        memberInfos.Add(memberInfo);
                }
            }
 
            return memberInfos.AsReadOnly();
        }
 
        internal static bool CreateField(ITypeDescriptorContext context, ActivityBind activityBind, bool throwOnError)
        {
            //Check if the activity is root activity and has valid design time type
            if (!String.IsNullOrEmpty(activityBind.Path))
            {
                Type boundType = PropertyDescriptorUtils.GetBaseType(context.PropertyDescriptor, context.Instance, context);
                Activity activity = PropertyDescriptorUtils.GetComponent(context) as Activity;
                if (activity != null && boundType != null)
                {
                    activity = Helpers.ParseActivityForBind(activity, activityBind.Name);
                    if (activity == Helpers.GetRootActivity(activity))
                    {
                        bool isVB = (CompilerHelpers.GetSupportedLanguage(context) == SupportedLanguages.VB);
                        Type designedType = Helpers.GetDataSourceClass(activity, context);
                        if (designedType != null)
                        {
                            //field path could be nested too.
                            //need to find field only with the name up to the first dot (CimplexTypeField in the example below)
                            //and the right type (that would be tricky if the field doesnt exist yet)
                            //example: CimplexTypeField.myIDictionary_int_string[10].someOtherGood2
 
                            string fieldName = activityBind.Path;
                            int indexOfDot = fieldName.IndexOfAny(new char[] { '.', '/', '[' });
                            if (indexOfDot != -1)
                                fieldName = fieldName.Substring(0, indexOfDot); //path is a nested field access
 
                            MemberInfo matchingMember = ActivityBindPropertyDescriptor.FindMatchingMember(fieldName, designedType, isVB);
                            if (matchingMember != null)
                            {
                                Type memberType = null;
                                bool isPrivate = false;
                                if (matchingMember is FieldInfo)
                                {
                                    isPrivate = ((FieldInfo)matchingMember).IsPrivate;
                                    memberType = ((FieldInfo)matchingMember).FieldType;
                                }
                                else if (matchingMember is PropertyInfo)
                                {
                                    MethodInfo getMethod = ((PropertyInfo)matchingMember).GetGetMethod();
                                    MethodInfo setMethod = ((PropertyInfo)matchingMember).GetSetMethod();
                                    isPrivate = ((getMethod != null && getMethod.IsPrivate) || (setMethod != null && setMethod.IsPrivate));
                                }
                                else if (matchingMember is MethodInfo)
                                {
                                    isPrivate = ((MethodInfo)matchingMember).IsPrivate;
                                }
 
                                if (indexOfDot != -1)
                                { //need to find the type of the member the path references (and if the path is valid at all)
                                    PathWalker pathWalker = new PathWalker();
                                    PathMemberInfoEventArgs finalEventArgs = null;
                                    pathWalker.MemberFound += delegate(object sender, PathMemberInfoEventArgs eventArgs)
                                    { finalEventArgs = eventArgs; };
 
                                    if (pathWalker.TryWalkPropertyPath(designedType, activityBind.Path))
                                    {
                                        //successfully walked the entire path
                                        memberType = BindHelpers.GetMemberType(finalEventArgs.MemberInfo);
                                    }
                                    else
                                    {
                                        //the path is invalid
                                        if (throwOnError)
                                            throw new InvalidOperationException(SR.GetString(SR.Error_MemberWithSameNameExists, activityBind.Path, designedType.FullName));
 
                                        return false;
                                    }
                                }
 
                                if ((matchingMember.DeclaringType == designedType || !isPrivate) &&
                                    matchingMember is FieldInfo &&
                                    TypeProvider.IsAssignable(boundType, memberType))
                                {
                                    return true;
                                }
                                else
                                {
                                    if (throwOnError)
                                        throw new InvalidOperationException(SR.GetString(SR.Error_MemberWithSameNameExists, activityBind.Path, designedType.FullName));
                                    return false;
                                }
                            }
                            else
                            {
                                // Find out if the name conflicts with an existing activity that has not be flushed in to the 
                                // code beside.  An activity bind can bind to this field only if the type of the property
                                // is the assignable from the activity type.
                                Activity matchingActivity = null;
                                if (string.Compare(activity.Name, fieldName, isVB ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal) == 0)
                                    matchingActivity = activity;
                                else if (activity is CompositeActivity)
                                {
                                    if (activity is CompositeActivity)
                                    {
                                        foreach (Activity existingActivity in Helpers.GetAllNestedActivities(activity as CompositeActivity))
                                        {
                                            if (string.Compare(existingActivity.Name, fieldName, isVB ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal) == 0)
                                                matchingActivity = existingActivity;
                                        }
                                    }
                                }
 
                                if (matchingActivity != null)
                                {
                                    if (TypeProvider.IsAssignable(boundType, matchingActivity.GetType()))
                                        return true;
                                    else
                                    {
                                        if (throwOnError)
                                            throw new InvalidOperationException(SR.GetString(SR.Error_MemberWithSameNameExists, activityBind.Path, designedType.FullName));
                                        return false;
                                    }
                                }
                            }
 
                            IMemberCreationService memberCreationService = context.GetService(typeof(IMemberCreationService)) as IMemberCreationService;
                            if (memberCreationService == null)
                            {
                                if (throwOnError)
                                    throw new InvalidOperationException(SR.GetString(SR.General_MissingService, typeof(IMemberCreationService).FullName));
                            }
                            else
                            {
                                IDesignerHost designerHost = context.GetService(typeof(IDesignerHost)) as IDesignerHost;
                                if (designerHost == null)
                                {
                                    if (throwOnError)
                                        throw new InvalidOperationException(SR.GetString("General_MissingService", typeof(IDesignerHost).FullName));
                                }
                                else
                                {
                                    memberCreationService.CreateField(designerHost.RootComponentClassName, activityBind.Path, boundType, null, MemberAttributes.Public, null, false);
                                    return true;
                                }
                            }
                        }
                    }
                }
                else
                {
                    if (activity == null && throwOnError)
                        throw new InvalidOperationException(SR.GetString(SR.Error_InvalidActivityIdentifier, activityBind.Name));
 
                    if (boundType == null && throwOnError)
                        throw new InvalidOperationException(SR.GetString(SR.Error_PropertyTypeNotDefined, context.PropertyDescriptor.Name, typeof(ActivityBind).Name, typeof(IDynamicPropertyTypeProvider).Name));
                }
            }
 
            return false;
        }
 
        internal static bool IsBindableProperty(PropertyDescriptor propertyDescriptor)
        {
            //The property type itself is ActivityBind; we dont support such cases very well in componentmodel
            //but still we need to handle such cases as a fallback in ui
            if (propertyDescriptor.PropertyType == typeof(ActivityBind))
                return true;
 
            //We check this condition so that we will make sure that ActivityBind UI infrastructure
            //kicks into action in cases of parameter properties. User might sometimes do this on their properties
            //but in such cases they need to write their custom property descriptors just as we have written
            //ParameterInfoBasedPropertyDescriptor
            if (propertyDescriptor.Converter is ActivityBindTypeConverter)
                return true;
 
            //For all the other cases 
            DependencyProperty dependencyProperty = DependencyProperty.FromName(propertyDescriptor.Name, propertyDescriptor.ComponentType);
            if (typeof(DependencyObject).IsAssignableFrom(propertyDescriptor.ComponentType) && dependencyProperty != null && !dependencyProperty.DefaultMetadata.IsMetaProperty)
                return true;
 
            return false;
        }
 
        internal static MemberInfo FindMatchingMember(string name, Type ownerType, bool ignoreCase)
        {
            MemberInfo matchingMember = null;
            foreach (MemberInfo memberInfo in ownerType.GetMembers(BindingFlags.FlattenHierarchy | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic))
            {
                if (memberInfo.Name.Equals(name, ((ignoreCase) ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal)))
                {
                    matchingMember = memberInfo;
                    break;
                }
            }
            return matchingMember;
        }
        #endregion
    }
    #endregion
 
    #region Class ActivityBindNamePropertyDescriptor
    internal sealed class ActivityBindNamePropertyDescriptor : DynamicPropertyDescriptor
    {
        private ITypeDescriptorContext context;
 
        public ActivityBindNamePropertyDescriptor(ITypeDescriptorContext context, PropertyDescriptor realPropertyDescriptor)
            : base(context, realPropertyDescriptor)
        {
            this.context = context;
        }
 
        public override object GetValue(object component)
        {
            object value = base.GetValue(component);
            string id = value as string;
            if (!String.IsNullOrEmpty(id))
            {
                Activity activity = PropertyDescriptorUtils.GetComponent(this.context) as Activity;
                activity = (activity != null) ? Helpers.ParseActivityForBind(activity, id) : null;
                value = (activity != null) ? activity.QualifiedName : id;
            }
 
            return value;
        }
 
        public override void SetValue(object component, object value)
        {
            string id = value as string;
            if (String.IsNullOrEmpty(id))
                throw new InvalidOperationException(SR.GetString(SR.Error_ActivityIdentifierCanNotBeEmpty));
 
            Activity activity = PropertyDescriptorUtils.GetComponent(this.context) as Activity;
            if (activity != null)
            {
                if (Helpers.ParseActivityForBind(activity, id) == null)
                    throw new InvalidOperationException(SR.GetString(SR.Error_InvalidActivityIdentifier, id));
            }
 
            base.SetValue(component, value);
        }
    }
    #endregion
 
    #region Class ActivityBindPathPropertyDescriptor
    internal sealed class ActivityBindPathPropertyDescriptor : DynamicPropertyDescriptor
    {
        private ITypeDescriptorContext context;
 
        public ActivityBindPathPropertyDescriptor(ITypeDescriptorContext context, PropertyDescriptor realPropertyDescriptor)
            : base(context, realPropertyDescriptor)
        {
            this.context = context;
        }
 
        internal ITypeDescriptorContext OuterPropertyContext
        {
            get
            {
                return this.context;
            }
        }
    }
    #endregion
 
    #endregion
 
    #region ReadOnly Properties Integration
 
    #region Class ReadonlyTypeDescriptorProvider
    internal sealed class ReadonlyTypeDescriptonProvider : TypeDescriptionProvider
    {
        internal ReadonlyTypeDescriptonProvider(TypeDescriptionProvider realProvider)
            : base(realProvider)
        {
        }
 
        public override ICustomTypeDescriptor GetTypeDescriptor(Type type, object instance)
        {
            ICustomTypeDescriptor realTypeDescriptor = base.GetTypeDescriptor(type, instance);
            ICustomTypeDescriptor readonlyTypeDescriptor = new ReadonlyTypeDescriptor(realTypeDescriptor);
            return readonlyTypeDescriptor;
        }
    }
    #endregion
 
    #region Class ReadonlyTypeDescriptor
    internal sealed class ReadonlyTypeDescriptor : CustomTypeDescriptor
    {
        internal ReadonlyTypeDescriptor(ICustomTypeDescriptor realTypeDescriptor)
            : base(realTypeDescriptor)
        {
        }
 
        public override AttributeCollection GetAttributes()
        {
            ArrayList collection = new ArrayList();
            foreach (Attribute attribute in base.GetAttributes())
            {
                //should not have any editor attribute and only one readonly attribute
                if (!(attribute is EditorAttribute || attribute is ReadOnlyAttribute))
                    collection.Add(attribute);
            }
            collection.Add(new ReadOnlyAttribute(true));
            AttributeCollection newCollection = new AttributeCollection((Attribute[])collection.ToArray(typeof(Attribute)));
            return newCollection;
        }
 
        public override PropertyDescriptorCollection GetProperties()
        {
            PropertyDescriptorCollection properties = base.GetProperties();
 
            ArrayList readonlyProperties = new ArrayList();
            foreach (PropertyDescriptor property in properties)
            {
                BrowsableAttribute browsable = property.Attributes[typeof(BrowsableAttribute)] as BrowsableAttribute;
                if (browsable != null && browsable.Browsable && !(property is ReadonlyPropertyDescriptor))
                    readonlyProperties.Add(new ReadonlyPropertyDescriptor(property));
                else
                    readonlyProperties.Add(property);
            }
 
            return new PropertyDescriptorCollection((PropertyDescriptor[])readonlyProperties.ToArray(typeof(PropertyDescriptor)));
        }
 
        public override EventDescriptorCollection GetEvents(Attribute[] attributes)
        {
            EventDescriptorCollection events = base.GetEvents(attributes);
 
            ArrayList readonlyEvents = new ArrayList();
            foreach (EventDescriptor e in events)
            {
                BrowsableAttribute browsable = e.Attributes[typeof(BrowsableAttribute)] as BrowsableAttribute;
                if (browsable != null && browsable.Browsable)
                    readonlyEvents.Add(new ReadonlyEventDescriptor(e));
                else
                    readonlyEvents.Add(e);
            }
 
            return new EventDescriptorCollection((EventDescriptor[])readonlyEvents.ToArray(typeof(EventDescriptor)));
        }
    }
    #endregion
 
    #region Class ReadonlyPropertyDescriptor
    internal sealed class ReadonlyPropertyDescriptor : PropertyDescriptor
    {
        private PropertyDescriptor realPropertyDescriptor;
 
        internal ReadonlyPropertyDescriptor(PropertyDescriptor descriptor)
            : base(descriptor, null)
        {
            this.realPropertyDescriptor = descriptor;
        }
 
        public override string Category
        {
            get
            {
                return this.realPropertyDescriptor.Category;
            }
        }
        public override AttributeCollection Attributes
        {
            get
            {
                ArrayList collection = new ArrayList();
                foreach (Attribute attribute in this.realPropertyDescriptor.Attributes)
                {
                    //should not have any editor attribute and only one readonly attribute
                    if (!(attribute is EditorAttribute || attribute is ReadOnlyAttribute))
                        collection.Add(attribute);
                }
                collection.Add(new ReadOnlyAttribute(true));
                AttributeCollection newCollection = new AttributeCollection((Attribute[])collection.ToArray(typeof(Attribute)));
                return newCollection;
            }
        }
        public override TypeConverter Converter
        {
            get
            {
                return this.realPropertyDescriptor.Converter;
            }
        }
        public override string Description
        {
            get
            {
                return this.realPropertyDescriptor.Description;
            }
        }
        public override Type ComponentType
        {
            get
            {
                return this.realPropertyDescriptor.ComponentType;
            }
        }
        public override Type PropertyType
        {
            get
            {
                return this.realPropertyDescriptor.PropertyType;
            }
        }
        public override bool IsReadOnly
        {
            get
            {
                return true;
            }
        }
        public override void ResetValue(object component)
        {
            this.realPropertyDescriptor.ResetValue(component);
        }
        public override bool CanResetValue(object component)
        {
            return false;
        }
        public override bool ShouldSerializeValue(object component)
        {
            return this.realPropertyDescriptor.ShouldSerializeValue(component);
        }
        public override object GetValue(object component)
        {
            return this.realPropertyDescriptor.GetValue(component);
        }
        public override void SetValue(object component, object value)
        {
            //This is readonly property descriptor
            Debug.Assert(false, "SetValue should not be called on readonly property!");
        }
    }
    #endregion
 
    #region Class ReadonlyEventDescriptor
    internal sealed class ReadonlyEventDescriptor : EventDescriptor
    {
        private EventDescriptor realEventDescriptor;
 
        internal ReadonlyEventDescriptor(EventDescriptor e)
            : base(e, null)
        {
            this.realEventDescriptor = e;
        }
 
        public override string Category
        {
            get
            {
                return this.realEventDescriptor.Category;
            }
        }
        public override AttributeCollection Attributes
        {
            get
            {
                ArrayList collection = new ArrayList();
                foreach (Attribute attribute in this.realEventDescriptor.Attributes)
                {
                    //should not have any editor attribute and only one readonly attribute
                    if (!(attribute is EditorAttribute || attribute is ReadOnlyAttribute))
                        collection.Add(attribute);
                }
                collection.Add(new ReadOnlyAttribute(true));
                AttributeCollection newCollection = new AttributeCollection((Attribute[])collection.ToArray(typeof(Attribute)));
                return newCollection;
            }
        }
        public override string Description
        {
            get
            {
                return this.realEventDescriptor.Description;
            }
        }
        public override Type ComponentType
        {
            get
            {
                return this.realEventDescriptor.ComponentType;
            }
        }
        public override Type EventType
        {
            get
            {
                return this.realEventDescriptor.EventType;
            }
        }
        public override bool IsMulticast
        {
            get
            {
                return this.realEventDescriptor.IsMulticast;
            }
        }
 
        public override void AddEventHandler(object component, Delegate value)
        {
            //This is readonly event descriptor
        }
        public override void RemoveEventHandler(object component, Delegate value)
        {
            //This is readonly event descriptor
        }
    }
    #endregion
 
    #endregion
}