ActivityBindForm.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / cdf / src / WF / Common / AuthoringOM / Design / Dialogs / ActivityBindForm.cs / 1305376 / ActivityBindForm.cs

                            using System; 
using System.Collections.Generic;
using System.Globalization;
using System.ComponentModel;
using System.Data; 
using System.Drawing;
using System.Text; 
using System.Windows.Forms; 
using System.Workflow.ComponentModel;
using System.ComponentModel.Design; 
using System.Workflow.ComponentModel.Compiler;
using System.Reflection;
using System.Diagnostics;
using System.Collections.ObjectModel; 
using System.Windows.Forms.Design;
using System.Diagnostics.CodeAnalysis; 
 
namespace System.Workflow.ComponentModel.Design
{ 
    internal sealed partial class ActivityBindForm : Form
    {
        //ui control
        private ActivityBindFormWorkflowOutline workflowOutline = null; 

        private IServiceProvider serviceProvider = null; 
        private ITypeDescriptorContext context = null; 
        private Type boundType = null;
 
        //returns
        private ActivityBind binding = null;
        private bool createNew = false;//create new field or use existing
        private bool createNewProperty = false;//create property or field 
        private string newMemberName = string.Empty;
 
        private const string MemberTypeFormat = "MemberType#{0}";//non-localiazable, used for image list keys 

        private string ActivityBindDialogTitleFormat;// = "Bind '{0}' to Activity Property"; 
        private string PropertyAssignableFormat;// = "Selected property of type '{0}' is assignable to the target property type '{1}'.";
        private string DescriptionFormat;// = " It has description '{0}'.";
        private string EditIndex;// = " You may change index(es) on the selected tree item either by clicking on a node with the left mouse button or by pressing Alt-I.";
 
        private string PleaseSelectCorrectActivityProperty;// = "Select a property of type '{0}'. Currently selected property of type \"{1}\" isn't assignable to the target type.";
        private string PleaseSelectActivityProperty;// = "Select a property of type \"{0}\" on an activity from the workflow activity tree."; 
        private string IncorrectIndexChange;// = "New index expression \"{0}\" is incorrect."; 

        private string CreateNewMemberHelpFormat;// = "Enter new member name you want to be created on the root activity for property promotion, then choose the kind of member between either a field or a property.\nNew member will be of type '{0}'."; 

        System.Windows.Forms.ImageList memberTypes = null;
        List properties;
 
        public ActivityBindForm(IServiceProvider serviceProvider, ITypeDescriptorContext context)
        { 
            this.context = context; 
            this.serviceProvider = serviceProvider;
 
            InitializeComponent();
            this.createProperty.Checked = true;//make the property to be the default emitted entity

            this.helpTextBox.Multiline = true; 

            //Set dialog fonts 
            IUIService uisvc = (IUIService)this.serviceProvider.GetService(typeof(IUIService)); 
            if (uisvc != null)
                this.Font = (Font)uisvc.Styles["DialogFont"]; 

            //add images to the tree-view's imagelist
            System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(ActivityBindForm));
 
            ActivityBindDialogTitleFormat = resources.GetString("ActivityBindDialogTitleFormat");
            PropertyAssignableFormat = resources.GetString("PropertyAssignableFormat"); 
            DescriptionFormat = resources.GetString("DescriptionFormat"); 
            EditIndex = resources.GetString("EditIndex");
            PleaseSelectCorrectActivityProperty = resources.GetString("PleaseSelectCorrectActivityProperty"); 
            PleaseSelectActivityProperty = resources.GetString("PleaseSelectActivityProperty");
            IncorrectIndexChange = resources.GetString("IncorrectIndexChange");
            CreateNewMemberHelpFormat = resources.GetString("CreateNewMemberHelpFormat");
 
            this.memberTypes = new System.Windows.Forms.ImageList();
            this.memberTypes.ImageStream = ((System.Windows.Forms.ImageListStreamer)(resources.GetObject("memberTypes.ImageStream"))); 
            this.memberTypes.TransparentColor = AmbientTheme.TransparentColor; 
            //this.memberTypes.Images.SetKeyName(0, "Field_Public");
            //this.memberTypes.Images.SetKeyName(1, "Field_Internal"); 
            //this.memberTypes.Images.SetKeyName(2, "Field_Protected");
            //this.memberTypes.Images.SetKeyName(3, "Field_Private");
            //this.memberTypes.Images.SetKeyName(4, "Property_Public");
            //this.memberTypes.Images.SetKeyName(5, "Property_Internal"); 
            //this.memberTypes.Images.SetKeyName(6, "Property_Protected");
            //this.memberTypes.Images.SetKeyName(7, "Property_Private"); 
            //this.memberTypes.Images.SetKeyName(8, "Constant_Public"); 
            //this.memberTypes.Images.SetKeyName(9, "Constant_Internal");
            //this.memberTypes.Images.SetKeyName(10, "Constant_Protected"); 
            //this.memberTypes.Images.SetKeyName(11, "Constant_Private");
            //this.memberTypes.Images.SetKeyName(12, "Event_Public");
            //this.memberTypes.Images.SetKeyName(13, "Event_Internal");
            //this.memberTypes.Images.SetKeyName(14, "Event_Protected"); 
            //this.memberTypes.Images.SetKeyName(15, "Event_Private");
            //this.memberTypes.Images.SetKeyName(16, "Delegate_Public"); 
            //this.memberTypes.Images.SetKeyName(17, "Delegate_Internal"); 
            //this.memberTypes.Images.SetKeyName(18, "Delegate_Protected");
            //this.memberTypes.Images.SetKeyName(19, "Delegate_Private"); 
            //this.memberTypes.Images.SetKeyName(20, "Index_Public");
            //this.memberTypes.Images.SetKeyName(21, "Index_Internal");
            //this.memberTypes.Images.SetKeyName(22, "Index_Protected");
            //this.memberTypes.Images.SetKeyName(23, "Index_Private"); 

            //preload custom properties before getting type from the type provider (as it would refresh the types) 
            this.properties = CustomActivityDesignerHelper.GetCustomProperties(context); 

        } 

        #region return properties
        public ActivityBind Binding
        { 
            get
            { 
                return this.binding; 
            }
        } 
        public bool CreateNew
        {
            get
            { 
                return this.createNew;
            } 
        } 
        public bool CreateNewProperty
        { 
            get
            {
                return this.createNewProperty;
            } 
        }
        public string NewMemberName 
        { 
            get
            { 
                return this.newMemberName;
            }
        }
        #endregion 

        private void ActivityBindForm_Load(object sender, EventArgs e) 
        { 
            this.Text = string.Format(CultureInfo.CurrentCulture, ActivityBindDialogTitleFormat, context.PropertyDescriptor.Name);
 

            if (this.context.PropertyDescriptor is DynamicPropertyDescriptor)
                this.boundType = PropertyDescriptorUtils.GetBaseType(this.context.PropertyDescriptor, PropertyDescriptorUtils.GetComponent(context), serviceProvider);
 
            if (this.boundType != null)
            { 
                //lets get the same type through the type provider (otherwise this type may mismatch with the one obtained from the design time types) 
                ITypeProvider typeProvider = this.serviceProvider.GetService(typeof(ITypeProvider)) as ITypeProvider;
                if (typeProvider != null) 
                {
                    Type designTimeType = typeProvider.GetType(this.boundType.FullName, false);
                    this.boundType = (designTimeType != null) ? designTimeType : this.boundType;
                } 
            }
 
            //create outline control 
            this.workflowOutline = new ActivityBindFormWorkflowOutline(this.serviceProvider, this);
            this.dummyPanel.BorderStyle = BorderStyle.None; 
            this.dummyPanel.SuspendLayout();
            this.dummyPanel.Controls.Add(this.workflowOutline);
            this.workflowOutline.Location = new Point(3, 3);
            this.workflowOutline.Size = new Size(199, 351); 
            this.workflowOutline.Dock = DockStyle.Fill;
            this.dummyPanel.ResumeLayout(false); 
 
            this.workflowOutline.AddMemberKindImages(this.memberTypes);
 
            //make the outline view load initial state
            this.workflowOutline.ReloadWorkflowOutline();

            //expand just the root node 
            this.workflowOutline.ExpandRootNode();
 
            //now we need to select the activity/path which was previously set 
            //NOTE: we would have to expand all nodes on the way to make doc outline control populate their children
            Activity activity = PropertyDescriptorUtils.GetComponent(context) as Activity; 
            if (activity == null)
            {
                IReferenceService rs = this.context.GetService(typeof(IReferenceService)) as IReferenceService;
                if (rs != null) 
                    activity = rs.GetComponent(this.context.Instance) as Activity;
            } 
 
            ActivityBind previousBinding = context.PropertyDescriptor.GetValue(context.Instance) as ActivityBind;
            if (activity != null && previousBinding != null) 
            {
                Activity previousBindActivity = Helpers.ParseActivity(Helpers.GetRootActivity(activity), previousBinding.Name);
                if (previousBindActivity != null)
                    this.workflowOutline.SelectActivity(previousBindActivity, ParseStringPath(GetActivityType(previousBindActivity), previousBinding.Path)); 
            }
 
            if (this.properties != null) 
            {
                List customPropertyNames = new List(); 
                foreach (CustomProperty customProperty in this.properties)
                    customPropertyNames.Add(customProperty.Name);

                // set default name 
                this.memberNameTextBox.Text = DesignerHelpers.GenerateUniqueIdentifier(this.serviceProvider, activity.Name + "_" + context.PropertyDescriptor.Name, customPropertyNames.ToArray());
            } 
 
            this.newMemberHelpTextBox.Lines = string.Format(CultureInfo.CurrentCulture, CreateNewMemberHelpFormat, GetSimpleTypeFullName(this.boundType)).Split(new char[] { '\n' });
        } 

        private void OKButton_Click(object sender, EventArgs e)
        {
            this.DialogResult = DialogResult.None; 

            this.createNew = (this.bindTabControl.SelectedIndex != this.bindTabControl.TabPages.IndexOf(this.existingMemberPage)); 
            if (this.createNew) 
            {
                // 
                this.createNewProperty = this.createProperty.Checked;
                this.newMemberName = this.memberNameTextBox.Text;
                //validate name based on the prop promotion dialog
                this.DialogResult = ValidateNewMemberBind(this.newMemberName); 
            }
            else 
            { 
                this.DialogResult = ValidateExistingPropertyBind();
            } 
        }

        private DialogResult ValidateExistingPropertyBind()
        { 
            Activity activity = this.workflowOutline.SelectedActivity;
            PathInfo member = this.workflowOutline.SelectedMember; 
            string propertyPath = this.workflowOutline.PropertyPath;//the path on the PathInfo will be incorrect if user had changed indexes 

            if (activity == null || member == null) 
            {
                string message = SR.GetString(SR.Error_BindDialogNoValidPropertySelected, GetSimpleTypeFullName(this.boundType));
                DesignerHelpers.ShowError(this.serviceProvider, message);
                return DialogResult.None; 
            }
 
            Type parsedPropertyType = member.PropertyType; 
            //lets get the same type through the type provider (otherwise this type may mismatch with the one obtained from the design time types)
            ITypeProvider typeProvider = this.serviceProvider.GetService(typeof(ITypeProvider)) as ITypeProvider; 
            if (typeProvider != null && parsedPropertyType != null)
            {
                Type designTimeParsedType = typeProvider.GetType(parsedPropertyType.FullName, false);
                parsedPropertyType = (designTimeParsedType != null) ? designTimeParsedType : parsedPropertyType; 
            }
 
            if (this.boundType != parsedPropertyType && !TypeProvider.IsAssignable(this.boundType, parsedPropertyType)) 
            {
                string message = SR.GetString(SR.Error_BindDialogWrongPropertyType, GetSimpleTypeFullName(parsedPropertyType), GetSimpleTypeFullName(this.boundType)); 
                DesignerHelpers.ShowError(this.serviceProvider, message);
                return DialogResult.None;
            }
 
            //this is the selected activity which property is being bound
            Activity bindingActivity = PropertyDescriptorUtils.GetComponent(this.context) as Activity; 
 
            //this is the name of the property we are binding
            string propertyName = context.PropertyDescriptor.Name; 
            if (bindingActivity == activity && member != null && member.Path.Equals(propertyName, StringComparison.Ordinal))
            {
                DesignerHelpers.ShowError(this.serviceProvider, SR.GetString(SR.Error_BindDialogCanNotBindToItself));
                return DialogResult.None; 
            }
 
            if (activity != null && member != null) 
            {
                // 
                ActivityBind bind = new ActivityBind(activity.QualifiedName, propertyPath);

                ValidationManager manager = new ValidationManager(this.serviceProvider);
                PropertyValidationContext propertyValidationContext = new PropertyValidationContext(this.context.Instance, DependencyProperty.FromName(this.context.PropertyDescriptor.Name, this.context.Instance.GetType())); 
                manager.Context.Append(this.context.Instance);//
 
                ValidationErrorCollection errors; 
                using (WorkflowCompilationContext.CreateScope(manager))
                { 
                    errors = ValidationHelpers.ValidateProperty(manager, bindingActivity, bind, propertyValidationContext);
                }
                if (errors != null && errors.Count > 0 && errors.HasErrors)
                { 
                    string message = string.Empty;
                    for (int i = 0; i < errors.Count; i++) 
                    { 
                        ValidationError error = errors[i];
                        message += error.ErrorText + ((i == errors.Count - 1) ? string.Empty : "; "); 
                    }

                    message = SR.GetString(SR.Error_BindDialogBindNotValid) + message;
                    DesignerHelpers.ShowError(this.serviceProvider, message); 
                    return DialogResult.None;
                } 
                else 
                {
                    this.binding = bind; 
                    return DialogResult.OK;
                }
            }
 
            return DialogResult.None;
        } 
 

        [SuppressMessage("Microsoft.Globalization", "CA130:UseOrdinalStringComparison", MessageId="System.String.Compare(System.String,System.String,System.Boolean,System.Globalization.CultureInfo)", Justification="This is a design time method and so there is no security issue")] 
        private DialogResult ValidateNewMemberBind(string newMemberName)
        {
            Activity activity = PropertyDescriptorUtils.GetComponent(context) as Activity;
            if (activity == null) 
            {
                IReferenceService rs = this.context.GetService(typeof(IReferenceService)) as IReferenceService; 
                if (rs != null) 
                    activity = rs.GetComponent(this.context.Instance) as Activity;
            } 

            string errorMsg = null;
            try
            { 
                ValidationHelpers.ValidateIdentifier(context, newMemberName);
            } 
            catch 
            {
                errorMsg = SR.GetString(SR.Error_InvalidLanguageIdentifier, newMemberName); 
            }

            // get all the members of the custom activity to ensure uniqueness
            Type customActivityType = CustomActivityDesignerHelper.GetCustomActivityType(context); 
            SupportedLanguages language = CompilerHelpers.GetSupportedLanguage(context);
            foreach (MemberInfo memberInfo in customActivityType.GetMembers(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static)) 
            { 
                if (string.Compare(memberInfo.Name, newMemberName, language == SupportedLanguages.VB, CultureInfo.InvariantCulture) == 0)
                { 
                    errorMsg = SR.GetString(SR.Failure_FieldAlreadyExist);
                    break;
                }
            } 

            // ctor name should be checked separately 
            if (errorMsg == null && string.Compare(customActivityType.Name, newMemberName, language == SupportedLanguages.VB, CultureInfo.InvariantCulture) == 0) 
                errorMsg = SR.GetString(SR.Failure_FieldAlreadyExist);
 
            if (errorMsg == null)
            {
                ActivityBind newBind = new ActivityBind(ActivityBind.GetRelativePathExpression(Helpers.GetRootActivity(activity), activity), newMemberName);
                IDesignerHost host = this.context.GetService(typeof(IDesignerHost)) as IDesignerHost; 
                if (host == null)
                    throw new InvalidOperationException(SR.GetString(SR.General_MissingService, typeof(IDesignerHost).FullName)); 
                this.binding = newBind; 
            }
            else 
            {
                DesignerHelpers.ShowError(context, errorMsg);
            }
 
            return ((errorMsg == null) ? DialogResult.OK : DialogResult.None);
        } 
 
        private void cancelButton_Click(object sender, EventArgs e)
        { 
            this.DialogResult = DialogResult.Cancel;
        }

        private void SelectedActivityChanged(Activity activity, PathInfo memberPathInfo, string path) 
        {
            string helpMessage = string.Empty; 
            string desiredType = GetSimpleTypeFullName(this.boundType); 

            if (memberPathInfo != null) 
            {
                if (path == null || path.Length == 0)
                {
                    helpMessage = string.Format(CultureInfo.CurrentCulture, PleaseSelectActivityProperty, desiredType); 
                }
                else 
                { 
                    string memberName = MemberActivityBindTreeNode.MemberName(memberPathInfo.Path);
                    string memberType = GetSimpleTypeFullName(memberPathInfo.PropertyType); 
                    string memberDescription = GetMemberDescription(memberPathInfo.MemberInfo);

                    if (TypeProvider.IsAssignable(this.boundType, memberPathInfo.PropertyType))
                        helpMessage = string.Format(CultureInfo.CurrentCulture, PropertyAssignableFormat, memberType, desiredType) + ((memberDescription.Length > 0) ? string.Format(CultureInfo.CurrentCulture, DescriptionFormat, memberDescription) : string.Empty); 
                    else
                        helpMessage = string.Format(CultureInfo.CurrentCulture, PleaseSelectCorrectActivityProperty, desiredType, memberType); 
 
                    helpMessage += ((MemberActivityBindTreeNode.MemberName(path).IndexOfAny(new char[] { '[', ']' }) != -1) ? EditIndex : string.Empty);
                } 
            }
            else
            {
                helpMessage = string.Format(CultureInfo.CurrentCulture, PleaseSelectActivityProperty, desiredType); 
            }
 
            this.helpTextBox.Lines = helpMessage.Split(new char[]{'\n'}); 
        }
 
        private List PopulateAutoCompleteList(Activity activity, PathInfo path)
        {
            List currentPropertyList = new List();
            Type activityType = GetActivityType(activity); 
            PathInfo[] subProps = (activityType != null) ? ProcessPaths(activityType, path) : null;
            if (subProps != null) 
                currentPropertyList.AddRange(subProps); 

            return currentPropertyList; 
        }

        private Type GetActivityType(Activity activity)
        { 
            Type activityType = null;
 
            IDesignerHost designerHost = this.serviceProvider.GetService(typeof(IDesignerHost)) as IDesignerHost; 
            WorkflowDesignerLoader loader = this.serviceProvider.GetService(typeof(WorkflowDesignerLoader)) as WorkflowDesignerLoader;
            if (designerHost != null && loader != null && activity.Parent == null) 
            {
                ITypeProvider typeProvider = this.serviceProvider.GetService(typeof(ITypeProvider)) as ITypeProvider;
                if (typeProvider != null)
                    activityType = typeProvider.GetType(designerHost.RootComponentClassName, false); 
            }
 
            if (activityType == null) 
                activityType = activity.GetType();
 
            return activityType;
        }

        #region help - related 
        private void ActivityBindForm_HelpButtonClicked(object sender, CancelEventArgs e)
        { 
            e.Cancel = true; 
            GetHelp();
        } 

        protected override void OnHelpRequested(HelpEventArgs e)
        {
            e.Handled = true; 
            GetHelp();
        } 
 
        private void GetHelp()
        { 
            DesignerHelpers.ShowHelpFromKeyword(this.serviceProvider, typeof(ActivityBindForm).FullName + ".UI");
        }
        #endregion
 
        //given activity and current path, process all immediate children properties of the selected property
        private PathInfo[] ProcessPaths(Type activityType, PathInfo topProperty) 
        { 
            List paths = new List();
 
            if (topProperty == null)
            {
                paths.AddRange(GetSubPropertiesOnType(activityType, string.Empty));
            } 
            else //topProperty != null
            { 
                //sub properties on activity properties 
                paths.AddRange(GetSubPropertiesOnType(topProperty.PropertyType, topProperty.Path));
            } 

            return paths.ToArray();
        }
 
        private PathInfo[] GetArraySubProperties(Type propertyType, string currentPath)//(PathInfo pathInfo)
        { 
            List paths = new List(); 

            if (propertyType != typeof(string))//ignore char item[int] on the string 
            {
                List getterMethodInfos = new List();
                MemberInfo[] arrayMembers = null;
                try 
                {
                    arrayMembers = propertyType.GetDefaultMembers(); 
                } 
                catch (NotImplementedException)
                { 
                    //Even if we encounted a RTTTypeWrapper that doesnt implement GetDefaultMemebers dont crash.
                    //we should atleast be able to continue to bind to other members of the type.
                }
                catch (ArgumentException) 
                {
                    // This is a work-around for DevDiv Bugs 109401.  Type.GetDefaultMembers() can throw 
                    // ArgumentException in certain circumstances.  In order to avoid crashing the designer host 
                    // (typically VS), we must handle the exception and ignore the offending type.
                } 
                if (arrayMembers != null && arrayMembers.Length > 0)
                {
                    foreach (MemberInfo member in arrayMembers)
                    { 
                        if (member is PropertyInfo)
                            getterMethodInfos.Add((member as PropertyInfo).GetGetMethod()); 
                    } 
                }
 
                if (propertyType.IsArray)
                {
                    MemberInfo[] getMembers = propertyType.GetMember("Get");//arrays will always implement that
                    if (getMembers != null && getMembers.Length > 0) 
                    {
                        foreach (MemberInfo member in getMembers) 
                            if (member is MethodInfo) 
                                getterMethodInfos.Add(member as MethodInfo);
                    } 
                }

                foreach (MethodInfo info in getterMethodInfos)
                { 
                    string indexString = ConstructIndexString(info);
                    if (indexString != null) 
                    { 
                        //add array accessor
                        paths.Add(new PathInfo(currentPath + indexString, info, info.ReturnType)); 
                    }
                }
            }
 
            return paths.ToArray();
        } 
 
        private string ConstructIndexString(MethodInfo getterMethod)
        { 
            StringBuilder indexString = new StringBuilder();

            ParameterInfo[] parameters = getterMethod.GetParameters();
            if (parameters != null && parameters.Length > 0) 
            {
                indexString.Append("["); 
 
                for (int i = 0; i < parameters.Length; i++)
                { 
                    ParameterInfo parameter = parameters[i];
                    string subIndex = GetIndexerString(parameter.ParameterType);
                    if (subIndex == null)
                        return null; 

                    indexString.Append(subIndex); 
                    if (i < parameters.Length - 1) 
                        indexString.Append(",");
                } 

                indexString.Append("]");
            }
 
            return indexString.ToString();
        } 
 
        private string GetIndexerString(Type indexType)
        { 
            //The primitive types are Boolean, Byte, SByte, Int16, UInt16, Int32, UInt32, Int64, UInt64, Char, Double, and Single.
            object defaultIndexerInstance = null;
            if (IsTypePrimitive(indexType))
            { 
                try
                { 
                    //we'll just new the instance and get the string value out of the default one 
                    defaultIndexerInstance = Activator.CreateInstance(indexType);
                } 
                catch
                {
                    defaultIndexerInstance = null;
                } 
            }
            else if (indexType == typeof(string)) 
            { 
                defaultIndexerInstance = "\"\"";
            } 

            return (defaultIndexerInstance != null) ? defaultIndexerInstance.ToString() : null;
        }
 
        PropertyInfo[] GetProperties(Type type)
        { 
            List members = new List(); 
            members.AddRange(type.GetProperties(BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance | BindingFlags.FlattenHierarchy));
            if (type.IsInterface) 
            {
                Type[] interfaces = type.GetInterfaces();
                foreach (Type implementedInterface in interfaces)
                { 
                    members.AddRange(implementedInterface.GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.FlattenHierarchy));
                } 
            } 

            return members.ToArray(); 
        }

        //quite expensive - uses reflection to go over all public properties/field/events
        private PathInfo[] GetSubPropertiesOnType(Type typeToGetPropertiesOn, string currentPath) 
        {
            List paths = new List(); 
 
            if (typeToGetPropertiesOn == typeof(string) || (TypeProvider.IsAssignable(typeof(System.Delegate), typeToGetPropertiesOn) && !this.boundType.IsSubclassOf(typeof(Delegate))))//ignore char item[int] on the string
                return paths.ToArray(); 

            currentPath = (string.IsNullOrEmpty(currentPath)) ? string.Empty : currentPath + ".";
            ITypeProvider typeProvider = this.serviceProvider.GetService(typeof(ITypeProvider)) as ITypeProvider;
 
            foreach (PropertyInfo property in GetProperties(typeToGetPropertiesOn))
            { 
                MethodInfo getterMethod = property.GetGetMethod(); 
                Type memberType = BindHelpers.GetMemberType(property);
                if (memberType == null) 
                    continue;

                if (typeProvider != null)
                { 
                    Type designTimeMemberType = typeProvider.GetType(memberType.FullName, false);
                    memberType = (designTimeMemberType != null) ? designTimeMemberType : memberType; 
                } 

                //if (memberType == typeof(WorkflowParameterBindingCollection) && string.IsNullOrEmpty(currentPath)) 
                //{
                //    //special case for the parameters collection on an activity itself (when path is empty)
                //    Activity activity = this.workflowOutline.SelectedActivity;
                //    if(getterMethod != null && typeToGetPropertiesOn == activity.GetType()) 
                //    {
                //        WorkflowParameterBindingCollection collection = getterMethod.Invoke(activity, null) as WorkflowParameterBindingCollection; 
                //        if (collection != null) 
                //        {
                //            foreach (WorkflowParameterBinding parameterBinding in collection) 
                //            {
                //                //note that the currentPath is always empty
                //                paths.Add(new PathInfo(property.Name + "[\"" + parameterBinding.ParameterName + "\"].Value", typeof(object)));
                //            } 
                //        }
                //    } 
                //} 

                //if it's a primitive and not equal to the desired type, skip it. 
                //skip properties of type object if the target property is not object
                if (IsPropertyBrowsable(property) &&
                    getterMethod != null && memberType != null &&
                    (!IsTypePrimitive(memberType) || TypeProvider.IsAssignable(this.boundType, memberType)) && 
                    !((this.boundType != typeof(object) && memberType == typeof(object))))
                { 
                    //some properties are indexers... analyze the parameters on the getter method 
                    // C#: at design time indexer property is called "this" while at runtime it gets renamed to "Item"
                    // VB: indexer is called Item at design and runtime . 
                    string propertyName = property.Name;
                    propertyName = currentPath + propertyName + ConstructIndexString(getterMethod);
                    paths.Add(new PathInfo(propertyName, property, memberType));
                    paths.AddRange(GetArraySubProperties(memberType, propertyName)); 
                }
            } 
 
            //
 
            foreach (FieldInfo field in typeToGetPropertiesOn.GetFields(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.FlattenHierarchy))//BindingFlags.Static is needed for the const fields
            {
                Type fieldType = BindHelpers.GetMemberType(field);
                if (fieldType == null) 
                    continue;
 
                if (TypeProvider.IsAssignable(typeof(DependencyProperty), fieldType)) 
                    continue;//dont want to show all static public dependency properties fields
 
                if (typeProvider != null)
                {
                    Type designTimeFieldType = typeProvider.GetType(fieldType.FullName, false);
                    fieldType = (designTimeFieldType != null) ? designTimeFieldType : fieldType; 
                }
 
                //if it's a primitive and not equal to the desired type, skip it. 
                //
                if (IsPropertyBrowsable(field) && fieldType != null && 
                    (!IsTypePrimitive(fieldType) || TypeProvider.IsAssignable(this.boundType, fieldType)) && //primitive fields should only be shown for primitive properties
                    !(this.boundType != typeof(object) && fieldType == typeof(object)) && //fields of type object should only be shown for properties of type object
                    !(!TypeProvider.IsAssignable(typeof(Delegate), this.boundType) && TypeProvider.IsAssignable(typeof(Delegate), fieldType)))//fields of type delegate should only be shown for delegate properties
                { 
                    string fieldName = currentPath + field.Name;
                    paths.Add(new PathInfo(fieldName, field, BindHelpers.GetMemberType(field))); 
                    paths.AddRange(GetArraySubProperties(fieldType, fieldName)); 
                }
            } 

            //we will populate events only if the target type is event (since it is always going to be the last valid entry in the path)
            if (this.boundType.IsSubclassOf(typeof(Delegate)))//System.MulticastDelegate ???
            { 
                foreach (EventInfo eventInfo in typeToGetPropertiesOn.GetEvents(BindingFlags.Public | BindingFlags.Instance | BindingFlags.FlattenHierarchy))
                { 
                    Type eventType = BindHelpers.GetMemberType(eventInfo); 
                    if (eventType == null)
                        continue; 

                    if (typeProvider != null)
                    {
                        Type designTimeEventType = typeProvider.GetType(eventType.FullName, false); 
                        eventType = (designTimeEventType != null) ? designTimeEventType : eventType;
                    } 
 
                    if (IsPropertyBrowsable(eventInfo) && eventType != null && TypeProvider.IsAssignable(this.boundType, eventType))
                        paths.Add(new PathInfo(currentPath + eventInfo.Name, eventInfo, eventType)); 
                }
            }

            return paths.ToArray(); 
        }
 
        private string GetMemberDescription(MemberInfo member) 
        {
            object[] descriptions = member.GetCustomAttributes(typeof(DescriptionAttribute), false); 
            if (descriptions != null && descriptions.Length > 0)
            {
                DescriptionAttribute description = descriptions[0] as DescriptionAttribute;
                return (description != null) ? description.Description : string.Empty; 
            }
 
            return string.Empty; 
        }
 
        //given user typed path, find all properties along it and return them in the list
        private List ParseStringPath(Type activityType, string path)
        {
            if (string.IsNullOrEmpty(path)) 
                return null;
 
            List pathInfoList = new List(); 

            PathWalker pathWalker = new PathWalker(); 
            PathMemberInfoEventArgs finalEventArgs = null;
            PathErrorInfoEventArgs errorEventArgs = null;
            pathWalker.MemberFound += delegate(object sender, PathMemberInfoEventArgs eventArgs)
            { 
                finalEventArgs = eventArgs; //store the latest args
                pathInfoList.Add(new PathInfo(eventArgs.Path, eventArgs.MemberInfo, BindHelpers.GetMemberType(eventArgs.MemberInfo))); 
            }; 
            pathWalker.PathErrorFound += delegate(object sender, PathErrorInfoEventArgs eventArgs)
            { 
                errorEventArgs = eventArgs; //store the error args
            };

            pathWalker.TryWalkPropertyPath(activityType, path); 
            return pathInfoList;
        } 
 
        private bool IsPropertyBrowsable(MemberInfo property)
        { 
            object[] attributes = property.GetCustomAttributes(typeof(BrowsableAttribute), false);
            if (attributes.Length > 0)
            {
                BrowsableAttribute attribute = attributes[0] as BrowsableAttribute; 
                if (attribute != null)
                    return attribute.Browsable; 
                else 
                {
                    AttributeInfoAttribute attributeInfoAttribute = attributes[0] as AttributeInfoAttribute; 
                    if (attributeInfoAttribute != null)
                    {
                        ReadOnlyCollection argumentValues = attributeInfoAttribute.AttributeInfo.ArgumentValues;
                        if (argumentValues.Count > 0) 
                            return Convert.ToBoolean(argumentValues[0], CultureInfo.InvariantCulture);
                    } 
                } 
            }
 
            return true;
        }

        //primitive types - we dont expand them 
        private static bool IsTypePrimitive(Type type)
        { 
            return type.IsPrimitive || type.IsEnum || type == typeof(Guid) || type == typeof(IntPtr) || type == typeof(string) || type == typeof(DateTime) || type == typeof(TimeSpan); 
        }
 
        //
        private string GetSimpleTypeFullName(Type type)
        {
            if (type == null) 
                return string.Empty;
 
            StringBuilder typeName = new StringBuilder(type.FullName); 
            Stack types = new Stack();
            types.Push(type); 

            while (types.Count > 0)
            {
                type = types.Pop(); 

                while (type.IsArray) 
                    type = type.GetElementType(); 

                if (type.IsGenericType && !type.IsGenericTypeDefinition) 
                {
                    foreach (Type parameterType in type.GetGenericArguments())
                    {
                        typeName.Replace("[" + parameterType.AssemblyQualifiedName + "]", GetSimpleTypeFullName(parameterType)); 
                        types.Push(parameterType);
                    } 
                } 
            }
 
            return typeName.ToString();
        }

        #region Class ActivityBindFormWorkflowOutline 
        internal enum BindMemberAccessKind
        { 
            Public = 0, Internal = 1, Protected = 2, Private = 3, 
        }
 
        internal enum BindMemberKind
        {
            Field = 0, Property = 4, Constant = 8, Event = 12, Delegate = 16, Index = 20 //Index doesnt have any image
        }; 

        //tree node to be used in the activity bind form for activity nodes 
        private class ActivityBindTreeNode : WorkflowOutlineNode 
        {
            public ActivityBindTreeNode(Activity activity) 
                : base(activity)
            { }
        }
 
        private class DummyActivityBindTreeNode : WorkflowOutlineNode
        { 
            public DummyActivityBindTreeNode(Activity activity) 
                : base(activity)
            { } 
        }

        //used for members of activities or their nested members
        private class MemberActivityBindTreeNode : ActivityBindTreeNode 
        {
            //all member nodes have activity property set to the closest activity in the tree 
            private PathInfo pathInfo = null; 
            private BindMemberKind kind = BindMemberKind.Property;
            private BindMemberAccessKind accessKind = BindMemberAccessKind.Public; 

            public MemberActivityBindTreeNode(Activity activity, PathInfo pathInfo)
                :base(activity)
            { 
                this.pathInfo = pathInfo;
 
                string memberName = MemberName(this.PathInfo.Path); 

                // Field Property Constant Event Delegate Index 
                if (this.pathInfo.MemberInfo is EventInfo)
                {
                    this.kind = BindMemberKind.Event;
                    this.accessKind = BindMemberAccessKind.Public;//this.accessKind = (this.pathInfo.MemberInfo as EventInfo).Attributes 
                }
                else if (this.pathInfo.MemberInfo is FieldInfo) 
                { 
                    FieldInfo fieldInfo = this.pathInfo.MemberInfo as FieldInfo;
                    if((fieldInfo.Attributes & FieldAttributes.Static) != 0 && (fieldInfo.Attributes & FieldAttributes.Literal) != 0) 
                    {
                        this.kind = BindMemberKind.Constant;
                    }
                    else 
                    {
                        if (TypeProvider.IsAssignable(typeof(Delegate), fieldInfo.FieldType)) 
                            this.kind = BindMemberKind.Delegate; 
                        else
                            this.kind = BindMemberKind.Field; 
                    }
                    this.accessKind = (fieldInfo.IsPublic) ? BindMemberAccessKind.Public : ((fieldInfo.IsFamily) ? BindMemberAccessKind.Internal : (fieldInfo.IsPrivate) ? BindMemberAccessKind.Private : BindMemberAccessKind.Protected);
                }
                else if (this.pathInfo.MemberInfo is PropertyInfo) 
                {
                    this.kind = BindMemberKind.Property; 
                    PropertyInfo propertyInfo = this.pathInfo.MemberInfo as PropertyInfo; 
                    this.accessKind = BindMemberAccessKind.Public;//
                } 
                else if (memberName.IndexOfAny("[]".ToCharArray()) != -1)
                {
                    this.kind = BindMemberKind.Index;
                    this.accessKind = BindMemberAccessKind.Public;// 
                }
                else 
                { 
                    this.kind = BindMemberKind.Property;
                    this.accessKind = BindMemberAccessKind.Public;// 
                }
            }

            public override void RefreshNode() 
            {
                base.RefreshNode(); 
                this.Text = MemberName(this.PathInfo.Path); 
                this.ForeColor = Color.DarkBlue;
            } 

            public PathInfo PathInfo
            {
                get 
                {
                    return this.pathInfo; 
                } 
                set
                { 
                    this.pathInfo = value;
                }
            }
 
            public bool MayHaveChildNodes
            { 
                get 
                {
                    Type memberType = (this.pathInfo != null) ? this.pathInfo.PropertyType : null; 
                    if (memberType == null)
                        return false;

                    if (IsTypePrimitive(memberType) || (TypeProvider.IsAssignable(typeof(System.Delegate), memberType)) || (memberType == typeof(object))) 
                        return false;
 
                    return true; 
                }
            } 

            public BindMemberKind MemberKind
            {
                get 
                {
                    return this.kind; 
                } 
            }
 
            public BindMemberAccessKind MemberAccessKind
            {
                get
                { 
                    return this.accessKind;
                } 
            } 

            internal static string MemberName(string path) 
            {
                string memberName = path;
                //need to show just the latest portion of the path
                int index = memberName.LastIndexOf('.'); 
                memberName = (index != -1 && (index + 1) < memberName.Length) ? memberName.Substring(index + 1) : memberName;
                return memberName; 
            } 
        }
 
        private class ActivityBindFormWorkflowOutline : WorkflowOutline
        {
            private ActivityBindForm parent = null;
            private Activity selectedActivity = null; 
            private PathInfo selectedPathInfo = null;
 
            public ActivityBindFormWorkflowOutline(IServiceProvider serviceProvider, ActivityBindForm parent) 
                : base(serviceProvider)
            { 
                this.parent = parent;
                base.NeedsExpandAll = false;

                this.Expanding += new System.Windows.Forms.TreeViewCancelEventHandler(this.treeView1_BeforeExpand); 

                base.TreeView.BeforeLabelEdit += new NodeLabelEditEventHandler(TreeView_BeforeLabelEdit); 
                base.TreeView.AfterLabelEdit += new NodeLabelEditEventHandler(TreeView_AfterLabelEdit); 
                base.TreeView.LabelEdit = true;
                base.TreeView.KeyDown += new KeyEventHandler(TreeView_KeyDown); 
            }

            void TreeView_KeyDown(object sender, KeyEventArgs e)
            { 
                //F2 -> start editing index
                if (e.KeyCode == Keys.F2 && base.TreeView.SelectedNode != null) 
                { 
                    base.TreeView.SelectedNode.BeginEdit();
                    e.Handled = true; 
                    e.SuppressKeyPress = true;
                }
            }
 
            void TreeView_BeforeLabelEdit(object sender, NodeLabelEditEventArgs e)
            { 
                //allow editing the label only if it's an array member 
                MemberActivityBindTreeNode memberNode = e.Node as MemberActivityBindTreeNode;
                e.CancelEdit = (memberNode == null) || !memberNode.Text.Contains("[") || !memberNode.Text.Contains("]"); 
            }

            void TreeView_AfterLabelEdit(object sender, NodeLabelEditEventArgs e)
            { 
                //
                string oldLabel = e.Node.Text; 
                string newLabel = e.Label; 
                if (oldLabel == null || newLabel == null)
                { 
                    e.CancelEdit = true;
                    return;
                }
 
                MemberActivityBindTreeNode memberNode = e.Node as MemberActivityBindTreeNode;
 
                bool incorrectChange = false; 
                //sanity check (member name has not been changed, still have opening/closing square brackets, same number of commas)
                if (newLabel.IndexOf("[", StringComparison.Ordinal) == -1 || !newLabel.EndsWith("]", StringComparison.Ordinal)) 
                {
                    incorrectChange = true;
                }
                else 
                {
                    string oldMemberName = oldLabel.Substring(0, oldLabel.IndexOf("[", StringComparison.Ordinal)); 
                    string newMemberName = newLabel.Substring(0, newLabel.IndexOf("[", StringComparison.Ordinal)); 
                    incorrectChange = !oldMemberName.Equals(newMemberName, StringComparison.Ordinal);
                } 

                //re-parse, update pathinfo member
                if (!incorrectChange)
                { 
                    ActivityBindTreeNode parentNode = memberNode.Parent as ActivityBindTreeNode;
                    MemberActivityBindTreeNode memberParentNode = parentNode as MemberActivityBindTreeNode; 
                    Type memberType = (memberParentNode != null) ? memberParentNode.PathInfo.PropertyType : this.parent.GetActivityType(parentNode.Activity); 
                    //we will try to parse just the latest member path since the previous is assumed to be valid
                    List reparsedPathInfoList = this.parent.ParseStringPath(memberType, newLabel); 
                    if (reparsedPathInfoList == null || reparsedPathInfoList.Count == 0)
                    {
                        incorrectChange = true;
                    } 
                    else
                    { 
                        PathInfo newPathInfo = reparsedPathInfoList[reparsedPathInfoList.Count - 1];//get the last item in the list 
                        if(newPathInfo.Path.Equals(newLabel, StringComparison.Ordinal))
                            memberNode.PathInfo = newPathInfo; 
                        else
                            incorrectChange = true;
                    }
                } 

                if (incorrectChange) 
                { 
                    DesignerHelpers.ShowError(this.parent.serviceProvider, string.Format(CultureInfo.CurrentCulture, this.parent.IncorrectIndexChange, newLabel));
                    e.CancelEdit = true; 
                }
            }

            private void treeView1_BeforeExpand(object sender, TreeViewCancelEventArgs e) 
            {
                //see if the first child is the dummy node, replace it with members... 
                ActivityBindTreeNode node = e.Node as ActivityBindTreeNode; 
                if (node != null)
                { 
                    if (node.Nodes.Count > 0 && (node.Nodes[0] is DummyActivityBindTreeNode))
                    {
                        //Poluate child members on this node...
                        MemberActivityBindTreeNode memberNode = node as MemberActivityBindTreeNode; 
                        List members = this.parent.PopulateAutoCompleteList(node.Activity, (memberNode != null) ? memberNode.PathInfo : null);
                        List nodes = new List(); 
                        foreach (PathInfo mamberPathInfo in members) 
                        {
                            MemberActivityBindTreeNode childMemberNode = CreateMemberNode(node.Activity, mamberPathInfo); 
                            if (childMemberNode != null)
                            {
                                RefreshNode(childMemberNode, false);
                                nodes.Add(childMemberNode); 
                            }
                        } 
 
                        base.TreeView.BeginUpdate();
                        try 
                        {
                            node.Nodes.RemoveAt(0);
                            e.Node.Nodes.AddRange(nodes.ToArray());
                        } 
                        finally
                        { 
                            base.TreeView.EndUpdate(); 
                        }
                    } 
                }
            }

            public void AddMemberKindImages(ImageList memberTypes) 
            {
                for (int i = 0;i pathInfoList)
            { 
                WorkflowOutlineNode node = base.GetNode(activity);
 
                //now walk all activity children along the property path list 
                if (node != null)
                { 
                    //expand the node to make sure dummy node is populated with the members
                    node.Expand();

                    if (pathInfoList != null && pathInfoList.Count > 0) 
                    {
                        for (int i = 0; i < pathInfoList.Count; i++) 
                        { 
 							//there are several options here - it could be a regular property, an array or an indexer property
							//we'd do couple attempts at trying to find the right node (taking into account the fact that indexes could be changed by the user) 

                            PathInfo currentPathInfo = pathInfoList[i];
                            MemberActivityBindTreeNode matchingChildNode = null;
 
                            //this is an indexer, there could have been a non-indexer before
                            int indexOfOpenBracket = currentPathInfo.Path.IndexOf('['); 
                            if (indexOfOpenBracket != -1) 
                            {
                                string indexPropertyName = currentPathInfo.Path.Substring(0, indexOfOpenBracket); 
                                if (node.Text.Equals(indexPropertyName, StringComparison.Ordinal))
                                {
                                    //need to get back to the parent and select a different child with an index
                                    //see if we need to get the properties on the parent node again... 
                                    if (i > 0 && pathInfoList[i - 1].Path.Equals(indexPropertyName, StringComparison.Ordinal))
                                        node = node.Parent as WorkflowOutlineNode; 
                                } 
                            }
 
                            //find a child node with the same PathInfo member as the given one
                            foreach (TreeNode childNode in node.Nodes)
                            {
                                MemberActivityBindTreeNode memberTreeNode = childNode as MemberActivityBindTreeNode; 
                                if (memberTreeNode != null && memberTreeNode.PathInfo.Equals(currentPathInfo))
                                { 
                                    matchingChildNode = memberTreeNode; 
                                    break;
                                } 

                                //actual indexes may be different from the default ones...
								//if it's a indexer property (this[]), indexes might mismatch
								if (memberTreeNode != null && memberTreeNode.Text.Contains("[") && currentPathInfo.Path.Contains("[")) 
                                {
                                    //need to compare parameter type index collections... 
 									string currentPropertyName = GetMemberNameFromIndexerName(currentPathInfo.Path); 
									string treeNodePropertyName = GetMemberNameFromIndexerName(memberTreeNode.Text);
                                    if (string.Equals(currentPropertyName, treeNodePropertyName, StringComparison.Ordinal) && IsSamePropertyIndexer(currentPathInfo.MemberInfo, memberTreeNode.PathInfo.MemberInfo)) 
                                    {
                                        matchingChildNode = memberTreeNode;
                                        memberTreeNode.PathInfo = currentPathInfo;
                                        memberTreeNode.Text = MemberActivityBindTreeNode.MemberName(currentPathInfo.Path); 
                                        break;
                                    } 
                                } 
                            }
 
                            //havent found matching tree node in the list of children - will exit
                            if (matchingChildNode == null)
                                break;
 
                            node = matchingChildNode;
                            node.Expand(); 
                        } 
                    }
 
                    base.TreeView.SelectedNode = node;

                    System.Windows.Forms.Timer timer = new System.Windows.Forms.Timer();
                    timer.Tick += new EventHandler(timer_Tick); 
                    timer.Interval = 50;
                    timer.Start(); 
                } 
            }
 
 			private string GetMemberNameFromIndexerName(string fullName)
 			{
				int indexOfSeparator = fullName.IndexOf('[');
 				if (indexOfSeparator != -1) 
					fullName = fullName.Substring(0, indexOfSeparator);
				return fullName; 
			} 

            private void timer_Tick(object sender, EventArgs e) 
            {
                System.Windows.Forms.Timer timer = sender as System.Windows.Forms.Timer;
                if (timer != null)
                { 
                    timer.Stop();
                    timer.Tick -= new EventHandler(timer_Tick); 
                } 

                if (base.TreeView.SelectedNode != null) 
                    base.TreeView.SelectedNode.EnsureVisible();

                this.Focus();
            } 

            private bool IsSamePropertyIndexer(MemberInfo member1, MemberInfo member2) 
            { 
                if (member1 == null || member2 == null)
                    return false; 

                PropertyInfo property1 = member1 as PropertyInfo;
                PropertyInfo property2 = member2 as PropertyInfo;
 
                MethodInfo methodInfo1 = member1 as MethodInfo;
                MethodInfo methodInfo2 = member2 as MethodInfo; 
 
                ParameterInfo[] parameters1 = (property1 != null) ? property1.GetIndexParameters() : (methodInfo1 != null) ? methodInfo1.GetParameters() : null;
                ParameterInfo[] parameters2 = (property2 != null) ? property2.GetIndexParameters() : (methodInfo2 != null) ? methodInfo2.GetParameters() : null; 

                if (parameters1 == null || parameters1.Length == 0 || parameters2 == null || parameters2.Length == 0 || parameters1.Length != parameters2.Length)
                    return false;
 
                for (int i = 0; i < parameters1.Length; i++)
                { 
                    if (parameters1[i].ParameterType != parameters2[i].ParameterType) 
                        return false;
                } 

                return true;
            }
 
            public void ExpandRootNode()
            { 
                TreeNode node = base.RootNode; 
                if (node != null)
                { 
                    node.Collapse();
                    node.Expand();
                }
            } 

            public Activity SelectedActivity 
            { 
                get
                { 
                    return this.selectedActivity;
                }
            }
            public PathInfo SelectedMember 
            {
                get 
                { 
                    return this.selectedPathInfo;
                } 
            }
            public string PropertyPath
            {
                get 
                {
                    MemberActivityBindTreeNode memberNode = base.TreeView.SelectedNode as MemberActivityBindTreeNode; 
                    string path = string.Empty; 
                    while (memberNode != null)
                    { 
                        path = (path.Length == 0) ? memberNode.Text : memberNode.Text + "." + path;
                        memberNode = memberNode.Parent as MemberActivityBindTreeNode;
                    }
                    return path; 
                }
            } 
        } 
        #endregion
 
        #region Class PathInfo
        private class PathInfo
        {
            private string path; 
            private MemberInfo memberInfo;
            private Type propertyType; 
 
            public PathInfo(string path, MemberInfo memberInfo, Type propertyType)
            { 
                if (string.IsNullOrEmpty(path))
                    throw new ArgumentNullException("path");
                if (propertyType == null)
                    throw new ArgumentNullException("propertyType"); 
                if (memberInfo == null)
                    throw new ArgumentNullException("memberInfo"); 
 
                this.path = path;
                this.propertyType = propertyType; 
                this.memberInfo = memberInfo;
            }

            public string Path 
            {
                get { return this.path; } 
            } 

            public MemberInfo MemberInfo 
            {
                get { return this.memberInfo; }
            }
 
            public Type PropertyType
            { 
                get { return this.propertyType; } 
            }
 
            //show bind's path information only (no activity id here)
            public override string ToString()
            {
                return this.path; 
            }
 
            public override bool Equals(object obj) 
            {
                PathInfo otherInfo = obj as PathInfo; 
                if (otherInfo == null)
                    return false;

                return this.path.Equals(otherInfo.path, StringComparison.Ordinal); 
            }
 
            public override int GetHashCode() 
            {
                return this.path.GetHashCode(); 
            }
        }
        #endregion
    } 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
using System; 
using System.Collections.Generic;
using System.Globalization;
using System.ComponentModel;
using System.Data; 
using System.Drawing;
using System.Text; 
using System.Windows.Forms; 
using System.Workflow.ComponentModel;
using System.ComponentModel.Design; 
using System.Workflow.ComponentModel.Compiler;
using System.Reflection;
using System.Diagnostics;
using System.Collections.ObjectModel; 
using System.Windows.Forms.Design;
using System.Diagnostics.CodeAnalysis; 
 
namespace System.Workflow.ComponentModel.Design
{ 
    internal sealed partial class ActivityBindForm : Form
    {
        //ui control
        private ActivityBindFormWorkflowOutline workflowOutline = null; 

        private IServiceProvider serviceProvider = null; 
        private ITypeDescriptorContext context = null; 
        private Type boundType = null;
 
        //returns
        private ActivityBind binding = null;
        private bool createNew = false;//create new field or use existing
        private bool createNewProperty = false;//create property or field 
        private string newMemberName = string.Empty;
 
        private const string MemberTypeFormat = "MemberType#{0}";//non-localiazable, used for image list keys 

        private string ActivityBindDialogTitleFormat;// = "Bind '{0}' to Activity Property"; 
        private string PropertyAssignableFormat;// = "Selected property of type '{0}' is assignable to the target property type '{1}'.";
        private string DescriptionFormat;// = " It has description '{0}'.";
        private string EditIndex;// = " You may change index(es) on the selected tree item either by clicking on a node with the left mouse button or by pressing Alt-I.";
 
        private string PleaseSelectCorrectActivityProperty;// = "Select a property of type '{0}'. Currently selected property of type \"{1}\" isn't assignable to the target type.";
        private string PleaseSelectActivityProperty;// = "Select a property of type \"{0}\" on an activity from the workflow activity tree."; 
        private string IncorrectIndexChange;// = "New index expression \"{0}\" is incorrect."; 

        private string CreateNewMemberHelpFormat;// = "Enter new member name you want to be created on the root activity for property promotion, then choose the kind of member between either a field or a property.\nNew member will be of type '{0}'."; 

        System.Windows.Forms.ImageList memberTypes = null;
        List properties;
 
        public ActivityBindForm(IServiceProvider serviceProvider, ITypeDescriptorContext context)
        { 
            this.context = context; 
            this.serviceProvider = serviceProvider;
 
            InitializeComponent();
            this.createProperty.Checked = true;//make the property to be the default emitted entity

            this.helpTextBox.Multiline = true; 

            //Set dialog fonts 
            IUIService uisvc = (IUIService)this.serviceProvider.GetService(typeof(IUIService)); 
            if (uisvc != null)
                this.Font = (Font)uisvc.Styles["DialogFont"]; 

            //add images to the tree-view's imagelist
            System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(ActivityBindForm));
 
            ActivityBindDialogTitleFormat = resources.GetString("ActivityBindDialogTitleFormat");
            PropertyAssignableFormat = resources.GetString("PropertyAssignableFormat"); 
            DescriptionFormat = resources.GetString("DescriptionFormat"); 
            EditIndex = resources.GetString("EditIndex");
            PleaseSelectCorrectActivityProperty = resources.GetString("PleaseSelectCorrectActivityProperty"); 
            PleaseSelectActivityProperty = resources.GetString("PleaseSelectActivityProperty");
            IncorrectIndexChange = resources.GetString("IncorrectIndexChange");
            CreateNewMemberHelpFormat = resources.GetString("CreateNewMemberHelpFormat");
 
            this.memberTypes = new System.Windows.Forms.ImageList();
            this.memberTypes.ImageStream = ((System.Windows.Forms.ImageListStreamer)(resources.GetObject("memberTypes.ImageStream"))); 
            this.memberTypes.TransparentColor = AmbientTheme.TransparentColor; 
            //this.memberTypes.Images.SetKeyName(0, "Field_Public");
            //this.memberTypes.Images.SetKeyName(1, "Field_Internal"); 
            //this.memberTypes.Images.SetKeyName(2, "Field_Protected");
            //this.memberTypes.Images.SetKeyName(3, "Field_Private");
            //this.memberTypes.Images.SetKeyName(4, "Property_Public");
            //this.memberTypes.Images.SetKeyName(5, "Property_Internal"); 
            //this.memberTypes.Images.SetKeyName(6, "Property_Protected");
            //this.memberTypes.Images.SetKeyName(7, "Property_Private"); 
            //this.memberTypes.Images.SetKeyName(8, "Constant_Public"); 
            //this.memberTypes.Images.SetKeyName(9, "Constant_Internal");
            //this.memberTypes.Images.SetKeyName(10, "Constant_Protected"); 
            //this.memberTypes.Images.SetKeyName(11, "Constant_Private");
            //this.memberTypes.Images.SetKeyName(12, "Event_Public");
            //this.memberTypes.Images.SetKeyName(13, "Event_Internal");
            //this.memberTypes.Images.SetKeyName(14, "Event_Protected"); 
            //this.memberTypes.Images.SetKeyName(15, "Event_Private");
            //this.memberTypes.Images.SetKeyName(16, "Delegate_Public"); 
            //this.memberTypes.Images.SetKeyName(17, "Delegate_Internal"); 
            //this.memberTypes.Images.SetKeyName(18, "Delegate_Protected");
            //this.memberTypes.Images.SetKeyName(19, "Delegate_Private"); 
            //this.memberTypes.Images.SetKeyName(20, "Index_Public");
            //this.memberTypes.Images.SetKeyName(21, "Index_Internal");
            //this.memberTypes.Images.SetKeyName(22, "Index_Protected");
            //this.memberTypes.Images.SetKeyName(23, "Index_Private"); 

            //preload custom properties before getting type from the type provider (as it would refresh the types) 
            this.properties = CustomActivityDesignerHelper.GetCustomProperties(context); 

        } 

        #region return properties
        public ActivityBind Binding
        { 
            get
            { 
                return this.binding; 
            }
        } 
        public bool CreateNew
        {
            get
            { 
                return this.createNew;
            } 
        } 
        public bool CreateNewProperty
        { 
            get
            {
                return this.createNewProperty;
            } 
        }
        public string NewMemberName 
        { 
            get
            { 
                return this.newMemberName;
            }
        }
        #endregion 

        private void ActivityBindForm_Load(object sender, EventArgs e) 
        { 
            this.Text = string.Format(CultureInfo.CurrentCulture, ActivityBindDialogTitleFormat, context.PropertyDescriptor.Name);
 

            if (this.context.PropertyDescriptor is DynamicPropertyDescriptor)
                this.boundType = PropertyDescriptorUtils.GetBaseType(this.context.PropertyDescriptor, PropertyDescriptorUtils.GetComponent(context), serviceProvider);
 
            if (this.boundType != null)
            { 
                //lets get the same type through the type provider (otherwise this type may mismatch with the one obtained from the design time types) 
                ITypeProvider typeProvider = this.serviceProvider.GetService(typeof(ITypeProvider)) as ITypeProvider;
                if (typeProvider != null) 
                {
                    Type designTimeType = typeProvider.GetType(this.boundType.FullName, false);
                    this.boundType = (designTimeType != null) ? designTimeType : this.boundType;
                } 
            }
 
            //create outline control 
            this.workflowOutline = new ActivityBindFormWorkflowOutline(this.serviceProvider, this);
            this.dummyPanel.BorderStyle = BorderStyle.None; 
            this.dummyPanel.SuspendLayout();
            this.dummyPanel.Controls.Add(this.workflowOutline);
            this.workflowOutline.Location = new Point(3, 3);
            this.workflowOutline.Size = new Size(199, 351); 
            this.workflowOutline.Dock = DockStyle.Fill;
            this.dummyPanel.ResumeLayout(false); 
 
            this.workflowOutline.AddMemberKindImages(this.memberTypes);
 
            //make the outline view load initial state
            this.workflowOutline.ReloadWorkflowOutline();

            //expand just the root node 
            this.workflowOutline.ExpandRootNode();
 
            //now we need to select the activity/path which was previously set 
            //NOTE: we would have to expand all nodes on the way to make doc outline control populate their children
            Activity activity = PropertyDescriptorUtils.GetComponent(context) as Activity; 
            if (activity == null)
            {
                IReferenceService rs = this.context.GetService(typeof(IReferenceService)) as IReferenceService;
                if (rs != null) 
                    activity = rs.GetComponent(this.context.Instance) as Activity;
            } 
 
            ActivityBind previousBinding = context.PropertyDescriptor.GetValue(context.Instance) as ActivityBind;
            if (activity != null && previousBinding != null) 
            {
                Activity previousBindActivity = Helpers.ParseActivity(Helpers.GetRootActivity(activity), previousBinding.Name);
                if (previousBindActivity != null)
                    this.workflowOutline.SelectActivity(previousBindActivity, ParseStringPath(GetActivityType(previousBindActivity), previousBinding.Path)); 
            }
 
            if (this.properties != null) 
            {
                List customPropertyNames = new List(); 
                foreach (CustomProperty customProperty in this.properties)
                    customPropertyNames.Add(customProperty.Name);

                // set default name 
                this.memberNameTextBox.Text = DesignerHelpers.GenerateUniqueIdentifier(this.serviceProvider, activity.Name + "_" + context.PropertyDescriptor.Name, customPropertyNames.ToArray());
            } 
 
            this.newMemberHelpTextBox.Lines = string.Format(CultureInfo.CurrentCulture, CreateNewMemberHelpFormat, GetSimpleTypeFullName(this.boundType)).Split(new char[] { '\n' });
        } 

        private void OKButton_Click(object sender, EventArgs e)
        {
            this.DialogResult = DialogResult.None; 

            this.createNew = (this.bindTabControl.SelectedIndex != this.bindTabControl.TabPages.IndexOf(this.existingMemberPage)); 
            if (this.createNew) 
            {
                // 
                this.createNewProperty = this.createProperty.Checked;
                this.newMemberName = this.memberNameTextBox.Text;
                //validate name based on the prop promotion dialog
                this.DialogResult = ValidateNewMemberBind(this.newMemberName); 
            }
            else 
            { 
                this.DialogResult = ValidateExistingPropertyBind();
            } 
        }

        private DialogResult ValidateExistingPropertyBind()
        { 
            Activity activity = this.workflowOutline.SelectedActivity;
            PathInfo member = this.workflowOutline.SelectedMember; 
            string propertyPath = this.workflowOutline.PropertyPath;//the path on the PathInfo will be incorrect if user had changed indexes 

            if (activity == null || member == null) 
            {
                string message = SR.GetString(SR.Error_BindDialogNoValidPropertySelected, GetSimpleTypeFullName(this.boundType));
                DesignerHelpers.ShowError(this.serviceProvider, message);
                return DialogResult.None; 
            }
 
            Type parsedPropertyType = member.PropertyType; 
            //lets get the same type through the type provider (otherwise this type may mismatch with the one obtained from the design time types)
            ITypeProvider typeProvider = this.serviceProvider.GetService(typeof(ITypeProvider)) as ITypeProvider; 
            if (typeProvider != null && parsedPropertyType != null)
            {
                Type designTimeParsedType = typeProvider.GetType(parsedPropertyType.FullName, false);
                parsedPropertyType = (designTimeParsedType != null) ? designTimeParsedType : parsedPropertyType; 
            }
 
            if (this.boundType != parsedPropertyType && !TypeProvider.IsAssignable(this.boundType, parsedPropertyType)) 
            {
                string message = SR.GetString(SR.Error_BindDialogWrongPropertyType, GetSimpleTypeFullName(parsedPropertyType), GetSimpleTypeFullName(this.boundType)); 
                DesignerHelpers.ShowError(this.serviceProvider, message);
                return DialogResult.None;
            }
 
            //this is the selected activity which property is being bound
            Activity bindingActivity = PropertyDescriptorUtils.GetComponent(this.context) as Activity; 
 
            //this is the name of the property we are binding
            string propertyName = context.PropertyDescriptor.Name; 
            if (bindingActivity == activity && member != null && member.Path.Equals(propertyName, StringComparison.Ordinal))
            {
                DesignerHelpers.ShowError(this.serviceProvider, SR.GetString(SR.Error_BindDialogCanNotBindToItself));
                return DialogResult.None; 
            }
 
            if (activity != null && member != null) 
            {
                // 
                ActivityBind bind = new ActivityBind(activity.QualifiedName, propertyPath);

                ValidationManager manager = new ValidationManager(this.serviceProvider);
                PropertyValidationContext propertyValidationContext = new PropertyValidationContext(this.context.Instance, DependencyProperty.FromName(this.context.PropertyDescriptor.Name, this.context.Instance.GetType())); 
                manager.Context.Append(this.context.Instance);//
 
                ValidationErrorCollection errors; 
                using (WorkflowCompilationContext.CreateScope(manager))
                { 
                    errors = ValidationHelpers.ValidateProperty(manager, bindingActivity, bind, propertyValidationContext);
                }
                if (errors != null && errors.Count > 0 && errors.HasErrors)
                { 
                    string message = string.Empty;
                    for (int i = 0; i < errors.Count; i++) 
                    { 
                        ValidationError error = errors[i];
                        message += error.ErrorText + ((i == errors.Count - 1) ? string.Empty : "; "); 
                    }

                    message = SR.GetString(SR.Error_BindDialogBindNotValid) + message;
                    DesignerHelpers.ShowError(this.serviceProvider, message); 
                    return DialogResult.None;
                } 
                else 
                {
                    this.binding = bind; 
                    return DialogResult.OK;
                }
            }
 
            return DialogResult.None;
        } 
 

        [SuppressMessage("Microsoft.Globalization", "CA130:UseOrdinalStringComparison", MessageId="System.String.Compare(System.String,System.String,System.Boolean,System.Globalization.CultureInfo)", Justification="This is a design time method and so there is no security issue")] 
        private DialogResult ValidateNewMemberBind(string newMemberName)
        {
            Activity activity = PropertyDescriptorUtils.GetComponent(context) as Activity;
            if (activity == null) 
            {
                IReferenceService rs = this.context.GetService(typeof(IReferenceService)) as IReferenceService; 
                if (rs != null) 
                    activity = rs.GetComponent(this.context.Instance) as Activity;
            } 

            string errorMsg = null;
            try
            { 
                ValidationHelpers.ValidateIdentifier(context, newMemberName);
            } 
            catch 
            {
                errorMsg = SR.GetString(SR.Error_InvalidLanguageIdentifier, newMemberName); 
            }

            // get all the members of the custom activity to ensure uniqueness
            Type customActivityType = CustomActivityDesignerHelper.GetCustomActivityType(context); 
            SupportedLanguages language = CompilerHelpers.GetSupportedLanguage(context);
            foreach (MemberInfo memberInfo in customActivityType.GetMembers(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static)) 
            { 
                if (string.Compare(memberInfo.Name, newMemberName, language == SupportedLanguages.VB, CultureInfo.InvariantCulture) == 0)
                { 
                    errorMsg = SR.GetString(SR.Failure_FieldAlreadyExist);
                    break;
                }
            } 

            // ctor name should be checked separately 
            if (errorMsg == null && string.Compare(customActivityType.Name, newMemberName, language == SupportedLanguages.VB, CultureInfo.InvariantCulture) == 0) 
                errorMsg = SR.GetString(SR.Failure_FieldAlreadyExist);
 
            if (errorMsg == null)
            {
                ActivityBind newBind = new ActivityBind(ActivityBind.GetRelativePathExpression(Helpers.GetRootActivity(activity), activity), newMemberName);
                IDesignerHost host = this.context.GetService(typeof(IDesignerHost)) as IDesignerHost; 
                if (host == null)
                    throw new InvalidOperationException(SR.GetString(SR.General_MissingService, typeof(IDesignerHost).FullName)); 
                this.binding = newBind; 
            }
            else 
            {
                DesignerHelpers.ShowError(context, errorMsg);
            }
 
            return ((errorMsg == null) ? DialogResult.OK : DialogResult.None);
        } 
 
        private void cancelButton_Click(object sender, EventArgs e)
        { 
            this.DialogResult = DialogResult.Cancel;
        }

        private void SelectedActivityChanged(Activity activity, PathInfo memberPathInfo, string path) 
        {
            string helpMessage = string.Empty; 
            string desiredType = GetSimpleTypeFullName(this.boundType); 

            if (memberPathInfo != null) 
            {
                if (path == null || path.Length == 0)
                {
                    helpMessage = string.Format(CultureInfo.CurrentCulture, PleaseSelectActivityProperty, desiredType); 
                }
                else 
                { 
                    string memberName = MemberActivityBindTreeNode.MemberName(memberPathInfo.Path);
                    string memberType = GetSimpleTypeFullName(memberPathInfo.PropertyType); 
                    string memberDescription = GetMemberDescription(memberPathInfo.MemberInfo);

                    if (TypeProvider.IsAssignable(this.boundType, memberPathInfo.PropertyType))
                        helpMessage = string.Format(CultureInfo.CurrentCulture, PropertyAssignableFormat, memberType, desiredType) + ((memberDescription.Length > 0) ? string.Format(CultureInfo.CurrentCulture, DescriptionFormat, memberDescription) : string.Empty); 
                    else
                        helpMessage = string.Format(CultureInfo.CurrentCulture, PleaseSelectCorrectActivityProperty, desiredType, memberType); 
 
                    helpMessage += ((MemberActivityBindTreeNode.MemberName(path).IndexOfAny(new char[] { '[', ']' }) != -1) ? EditIndex : string.Empty);
                } 
            }
            else
            {
                helpMessage = string.Format(CultureInfo.CurrentCulture, PleaseSelectActivityProperty, desiredType); 
            }
 
            this.helpTextBox.Lines = helpMessage.Split(new char[]{'\n'}); 
        }
 
        private List PopulateAutoCompleteList(Activity activity, PathInfo path)
        {
            List currentPropertyList = new List();
            Type activityType = GetActivityType(activity); 
            PathInfo[] subProps = (activityType != null) ? ProcessPaths(activityType, path) : null;
            if (subProps != null) 
                currentPropertyList.AddRange(subProps); 

            return currentPropertyList; 
        }

        private Type GetActivityType(Activity activity)
        { 
            Type activityType = null;
 
            IDesignerHost designerHost = this.serviceProvider.GetService(typeof(IDesignerHost)) as IDesignerHost; 
            WorkflowDesignerLoader loader = this.serviceProvider.GetService(typeof(WorkflowDesignerLoader)) as WorkflowDesignerLoader;
            if (designerHost != null && loader != null && activity.Parent == null) 
            {
                ITypeProvider typeProvider = this.serviceProvider.GetService(typeof(ITypeProvider)) as ITypeProvider;
                if (typeProvider != null)
                    activityType = typeProvider.GetType(designerHost.RootComponentClassName, false); 
            }
 
            if (activityType == null) 
                activityType = activity.GetType();
 
            return activityType;
        }

        #region help - related 
        private void ActivityBindForm_HelpButtonClicked(object sender, CancelEventArgs e)
        { 
            e.Cancel = true; 
            GetHelp();
        } 

        protected override void OnHelpRequested(HelpEventArgs e)
        {
            e.Handled = true; 
            GetHelp();
        } 
 
        private void GetHelp()
        { 
            DesignerHelpers.ShowHelpFromKeyword(this.serviceProvider, typeof(ActivityBindForm).FullName + ".UI");
        }
        #endregion
 
        //given activity and current path, process all immediate children properties of the selected property
        private PathInfo[] ProcessPaths(Type activityType, PathInfo topProperty) 
        { 
            List paths = new List();
 
            if (topProperty == null)
            {
                paths.AddRange(GetSubPropertiesOnType(activityType, string.Empty));
            } 
            else //topProperty != null
            { 
                //sub properties on activity properties 
                paths.AddRange(GetSubPropertiesOnType(topProperty.PropertyType, topProperty.Path));
            } 

            return paths.ToArray();
        }
 
        private PathInfo[] GetArraySubProperties(Type propertyType, string currentPath)//(PathInfo pathInfo)
        { 
            List paths = new List(); 

            if (propertyType != typeof(string))//ignore char item[int] on the string 
            {
                List getterMethodInfos = new List();
                MemberInfo[] arrayMembers = null;
                try 
                {
                    arrayMembers = propertyType.GetDefaultMembers(); 
                } 
                catch (NotImplementedException)
                { 
                    //Even if we encounted a RTTTypeWrapper that doesnt implement GetDefaultMemebers dont crash.
                    //we should atleast be able to continue to bind to other members of the type.
                }
                catch (ArgumentException) 
                {
                    // This is a work-around for DevDiv Bugs 109401.  Type.GetDefaultMembers() can throw 
                    // ArgumentException in certain circumstances.  In order to avoid crashing the designer host 
                    // (typically VS), we must handle the exception and ignore the offending type.
                } 
                if (arrayMembers != null && arrayMembers.Length > 0)
                {
                    foreach (MemberInfo member in arrayMembers)
                    { 
                        if (member is PropertyInfo)
                            getterMethodInfos.Add((member as PropertyInfo).GetGetMethod()); 
                    } 
                }
 
                if (propertyType.IsArray)
                {
                    MemberInfo[] getMembers = propertyType.GetMember("Get");//arrays will always implement that
                    if (getMembers != null && getMembers.Length > 0) 
                    {
                        foreach (MemberInfo member in getMembers) 
                            if (member is MethodInfo) 
                                getterMethodInfos.Add(member as MethodInfo);
                    } 
                }

                foreach (MethodInfo info in getterMethodInfos)
                { 
                    string indexString = ConstructIndexString(info);
                    if (indexString != null) 
                    { 
                        //add array accessor
                        paths.Add(new PathInfo(currentPath + indexString, info, info.ReturnType)); 
                    }
                }
            }
 
            return paths.ToArray();
        } 
 
        private string ConstructIndexString(MethodInfo getterMethod)
        { 
            StringBuilder indexString = new StringBuilder();

            ParameterInfo[] parameters = getterMethod.GetParameters();
            if (parameters != null && parameters.Length > 0) 
            {
                indexString.Append("["); 
 
                for (int i = 0; i < parameters.Length; i++)
                { 
                    ParameterInfo parameter = parameters[i];
                    string subIndex = GetIndexerString(parameter.ParameterType);
                    if (subIndex == null)
                        return null; 

                    indexString.Append(subIndex); 
                    if (i < parameters.Length - 1) 
                        indexString.Append(",");
                } 

                indexString.Append("]");
            }
 
            return indexString.ToString();
        } 
 
        private string GetIndexerString(Type indexType)
        { 
            //The primitive types are Boolean, Byte, SByte, Int16, UInt16, Int32, UInt32, Int64, UInt64, Char, Double, and Single.
            object defaultIndexerInstance = null;
            if (IsTypePrimitive(indexType))
            { 
                try
                { 
                    //we'll just new the instance and get the string value out of the default one 
                    defaultIndexerInstance = Activator.CreateInstance(indexType);
                } 
                catch
                {
                    defaultIndexerInstance = null;
                } 
            }
            else if (indexType == typeof(string)) 
            { 
                defaultIndexerInstance = "\"\"";
            } 

            return (defaultIndexerInstance != null) ? defaultIndexerInstance.ToString() : null;
        }
 
        PropertyInfo[] GetProperties(Type type)
        { 
            List members = new List(); 
            members.AddRange(type.GetProperties(BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance | BindingFlags.FlattenHierarchy));
            if (type.IsInterface) 
            {
                Type[] interfaces = type.GetInterfaces();
                foreach (Type implementedInterface in interfaces)
                { 
                    members.AddRange(implementedInterface.GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.FlattenHierarchy));
                } 
            } 

            return members.ToArray(); 
        }

        //quite expensive - uses reflection to go over all public properties/field/events
        private PathInfo[] GetSubPropertiesOnType(Type typeToGetPropertiesOn, string currentPath) 
        {
            List paths = new List(); 
 
            if (typeToGetPropertiesOn == typeof(string) || (TypeProvider.IsAssignable(typeof(System.Delegate), typeToGetPropertiesOn) && !this.boundType.IsSubclassOf(typeof(Delegate))))//ignore char item[int] on the string
                return paths.ToArray(); 

            currentPath = (string.IsNullOrEmpty(currentPath)) ? string.Empty : currentPath + ".";
            ITypeProvider typeProvider = this.serviceProvider.GetService(typeof(ITypeProvider)) as ITypeProvider;
 
            foreach (PropertyInfo property in GetProperties(typeToGetPropertiesOn))
            { 
                MethodInfo getterMethod = property.GetGetMethod(); 
                Type memberType = BindHelpers.GetMemberType(property);
                if (memberType == null) 
                    continue;

                if (typeProvider != null)
                { 
                    Type designTimeMemberType = typeProvider.GetType(memberType.FullName, false);
                    memberType = (designTimeMemberType != null) ? designTimeMemberType : memberType; 
                } 

                //if (memberType == typeof(WorkflowParameterBindingCollection) && string.IsNullOrEmpty(currentPath)) 
                //{
                //    //special case for the parameters collection on an activity itself (when path is empty)
                //    Activity activity = this.workflowOutline.SelectedActivity;
                //    if(getterMethod != null && typeToGetPropertiesOn == activity.GetType()) 
                //    {
                //        WorkflowParameterBindingCollection collection = getterMethod.Invoke(activity, null) as WorkflowParameterBindingCollection; 
                //        if (collection != null) 
                //        {
                //            foreach (WorkflowParameterBinding parameterBinding in collection) 
                //            {
                //                //note that the currentPath is always empty
                //                paths.Add(new PathInfo(property.Name + "[\"" + parameterBinding.ParameterName + "\"].Value", typeof(object)));
                //            } 
                //        }
                //    } 
                //} 

                //if it's a primitive and not equal to the desired type, skip it. 
                //skip properties of type object if the target property is not object
                if (IsPropertyBrowsable(property) &&
                    getterMethod != null && memberType != null &&
                    (!IsTypePrimitive(memberType) || TypeProvider.IsAssignable(this.boundType, memberType)) && 
                    !((this.boundType != typeof(object) && memberType == typeof(object))))
                { 
                    //some properties are indexers... analyze the parameters on the getter method 
                    // C#: at design time indexer property is called "this" while at runtime it gets renamed to "Item"
                    // VB: indexer is called Item at design and runtime . 
                    string propertyName = property.Name;
                    propertyName = currentPath + propertyName + ConstructIndexString(getterMethod);
                    paths.Add(new PathInfo(propertyName, property, memberType));
                    paths.AddRange(GetArraySubProperties(memberType, propertyName)); 
                }
            } 
 
            //
 
            foreach (FieldInfo field in typeToGetPropertiesOn.GetFields(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.FlattenHierarchy))//BindingFlags.Static is needed for the const fields
            {
                Type fieldType = BindHelpers.GetMemberType(field);
                if (fieldType == null) 
                    continue;
 
                if (TypeProvider.IsAssignable(typeof(DependencyProperty), fieldType)) 
                    continue;//dont want to show all static public dependency properties fields
 
                if (typeProvider != null)
                {
                    Type designTimeFieldType = typeProvider.GetType(fieldType.FullName, false);
                    fieldType = (designTimeFieldType != null) ? designTimeFieldType : fieldType; 
                }
 
                //if it's a primitive and not equal to the desired type, skip it. 
                //
                if (IsPropertyBrowsable(field) && fieldType != null && 
                    (!IsTypePrimitive(fieldType) || TypeProvider.IsAssignable(this.boundType, fieldType)) && //primitive fields should only be shown for primitive properties
                    !(this.boundType != typeof(object) && fieldType == typeof(object)) && //fields of type object should only be shown for properties of type object
                    !(!TypeProvider.IsAssignable(typeof(Delegate), this.boundType) && TypeProvider.IsAssignable(typeof(Delegate), fieldType)))//fields of type delegate should only be shown for delegate properties
                { 
                    string fieldName = currentPath + field.Name;
                    paths.Add(new PathInfo(fieldName, field, BindHelpers.GetMemberType(field))); 
                    paths.AddRange(GetArraySubProperties(fieldType, fieldName)); 
                }
            } 

            //we will populate events only if the target type is event (since it is always going to be the last valid entry in the path)
            if (this.boundType.IsSubclassOf(typeof(Delegate)))//System.MulticastDelegate ???
            { 
                foreach (EventInfo eventInfo in typeToGetPropertiesOn.GetEvents(BindingFlags.Public | BindingFlags.Instance | BindingFlags.FlattenHierarchy))
                { 
                    Type eventType = BindHelpers.GetMemberType(eventInfo); 
                    if (eventType == null)
                        continue; 

                    if (typeProvider != null)
                    {
                        Type designTimeEventType = typeProvider.GetType(eventType.FullName, false); 
                        eventType = (designTimeEventType != null) ? designTimeEventType : eventType;
                    } 
 
                    if (IsPropertyBrowsable(eventInfo) && eventType != null && TypeProvider.IsAssignable(this.boundType, eventType))
                        paths.Add(new PathInfo(currentPath + eventInfo.Name, eventInfo, eventType)); 
                }
            }

            return paths.ToArray(); 
        }
 
        private string GetMemberDescription(MemberInfo member) 
        {
            object[] descriptions = member.GetCustomAttributes(typeof(DescriptionAttribute), false); 
            if (descriptions != null && descriptions.Length > 0)
            {
                DescriptionAttribute description = descriptions[0] as DescriptionAttribute;
                return (description != null) ? description.Description : string.Empty; 
            }
 
            return string.Empty; 
        }
 
        //given user typed path, find all properties along it and return them in the list
        private List ParseStringPath(Type activityType, string path)
        {
            if (string.IsNullOrEmpty(path)) 
                return null;
 
            List pathInfoList = new List(); 

            PathWalker pathWalker = new PathWalker(); 
            PathMemberInfoEventArgs finalEventArgs = null;
            PathErrorInfoEventArgs errorEventArgs = null;
            pathWalker.MemberFound += delegate(object sender, PathMemberInfoEventArgs eventArgs)
            { 
                finalEventArgs = eventArgs; //store the latest args
                pathInfoList.Add(new PathInfo(eventArgs.Path, eventArgs.MemberInfo, BindHelpers.GetMemberType(eventArgs.MemberInfo))); 
            }; 
            pathWalker.PathErrorFound += delegate(object sender, PathErrorInfoEventArgs eventArgs)
            { 
                errorEventArgs = eventArgs; //store the error args
            };

            pathWalker.TryWalkPropertyPath(activityType, path); 
            return pathInfoList;
        } 
 
        private bool IsPropertyBrowsable(MemberInfo property)
        { 
            object[] attributes = property.GetCustomAttributes(typeof(BrowsableAttribute), false);
            if (attributes.Length > 0)
            {
                BrowsableAttribute attribute = attributes[0] as BrowsableAttribute; 
                if (attribute != null)
                    return attribute.Browsable; 
                else 
                {
                    AttributeInfoAttribute attributeInfoAttribute = attributes[0] as AttributeInfoAttribute; 
                    if (attributeInfoAttribute != null)
                    {
                        ReadOnlyCollection argumentValues = attributeInfoAttribute.AttributeInfo.ArgumentValues;
                        if (argumentValues.Count > 0) 
                            return Convert.ToBoolean(argumentValues[0], CultureInfo.InvariantCulture);
                    } 
                } 
            }
 
            return true;
        }

        //primitive types - we dont expand them 
        private static bool IsTypePrimitive(Type type)
        { 
            return type.IsPrimitive || type.IsEnum || type == typeof(Guid) || type == typeof(IntPtr) || type == typeof(string) || type == typeof(DateTime) || type == typeof(TimeSpan); 
        }
 
        //
        private string GetSimpleTypeFullName(Type type)
        {
            if (type == null) 
                return string.Empty;
 
            StringBuilder typeName = new StringBuilder(type.FullName); 
            Stack types = new Stack();
            types.Push(type); 

            while (types.Count > 0)
            {
                type = types.Pop(); 

                while (type.IsArray) 
                    type = type.GetElementType(); 

                if (type.IsGenericType && !type.IsGenericTypeDefinition) 
                {
                    foreach (Type parameterType in type.GetGenericArguments())
                    {
                        typeName.Replace("[" + parameterType.AssemblyQualifiedName + "]", GetSimpleTypeFullName(parameterType)); 
                        types.Push(parameterType);
                    } 
                } 
            }
 
            return typeName.ToString();
        }

        #region Class ActivityBindFormWorkflowOutline 
        internal enum BindMemberAccessKind
        { 
            Public = 0, Internal = 1, Protected = 2, Private = 3, 
        }
 
        internal enum BindMemberKind
        {
            Field = 0, Property = 4, Constant = 8, Event = 12, Delegate = 16, Index = 20 //Index doesnt have any image
        }; 

        //tree node to be used in the activity bind form for activity nodes 
        private class ActivityBindTreeNode : WorkflowOutlineNode 
        {
            public ActivityBindTreeNode(Activity activity) 
                : base(activity)
            { }
        }
 
        private class DummyActivityBindTreeNode : WorkflowOutlineNode
        { 
            public DummyActivityBindTreeNode(Activity activity) 
                : base(activity)
            { } 
        }

        //used for members of activities or their nested members
        private class MemberActivityBindTreeNode : ActivityBindTreeNode 
        {
            //all member nodes have activity property set to the closest activity in the tree 
            private PathInfo pathInfo = null; 
            private BindMemberKind kind = BindMemberKind.Property;
            private BindMemberAccessKind accessKind = BindMemberAccessKind.Public; 

            public MemberActivityBindTreeNode(Activity activity, PathInfo pathInfo)
                :base(activity)
            { 
                this.pathInfo = pathInfo;
 
                string memberName = MemberName(this.PathInfo.Path); 

                // Field Property Constant Event Delegate Index 
                if (this.pathInfo.MemberInfo is EventInfo)
                {
                    this.kind = BindMemberKind.Event;
                    this.accessKind = BindMemberAccessKind.Public;//this.accessKind = (this.pathInfo.MemberInfo as EventInfo).Attributes 
                }
                else if (this.pathInfo.MemberInfo is FieldInfo) 
                { 
                    FieldInfo fieldInfo = this.pathInfo.MemberInfo as FieldInfo;
                    if((fieldInfo.Attributes & FieldAttributes.Static) != 0 && (fieldInfo.Attributes & FieldAttributes.Literal) != 0) 
                    {
                        this.kind = BindMemberKind.Constant;
                    }
                    else 
                    {
                        if (TypeProvider.IsAssignable(typeof(Delegate), fieldInfo.FieldType)) 
                            this.kind = BindMemberKind.Delegate; 
                        else
                            this.kind = BindMemberKind.Field; 
                    }
                    this.accessKind = (fieldInfo.IsPublic) ? BindMemberAccessKind.Public : ((fieldInfo.IsFamily) ? BindMemberAccessKind.Internal : (fieldInfo.IsPrivate) ? BindMemberAccessKind.Private : BindMemberAccessKind.Protected);
                }
                else if (this.pathInfo.MemberInfo is PropertyInfo) 
                {
                    this.kind = BindMemberKind.Property; 
                    PropertyInfo propertyInfo = this.pathInfo.MemberInfo as PropertyInfo; 
                    this.accessKind = BindMemberAccessKind.Public;//
                } 
                else if (memberName.IndexOfAny("[]".ToCharArray()) != -1)
                {
                    this.kind = BindMemberKind.Index;
                    this.accessKind = BindMemberAccessKind.Public;// 
                }
                else 
                { 
                    this.kind = BindMemberKind.Property;
                    this.accessKind = BindMemberAccessKind.Public;// 
                }
            }

            public override void RefreshNode() 
            {
                base.RefreshNode(); 
                this.Text = MemberName(this.PathInfo.Path); 
                this.ForeColor = Color.DarkBlue;
            } 

            public PathInfo PathInfo
            {
                get 
                {
                    return this.pathInfo; 
                } 
                set
                { 
                    this.pathInfo = value;
                }
            }
 
            public bool MayHaveChildNodes
            { 
                get 
                {
                    Type memberType = (this.pathInfo != null) ? this.pathInfo.PropertyType : null; 
                    if (memberType == null)
                        return false;

                    if (IsTypePrimitive(memberType) || (TypeProvider.IsAssignable(typeof(System.Delegate), memberType)) || (memberType == typeof(object))) 
                        return false;
 
                    return true; 
                }
            } 

            public BindMemberKind MemberKind
            {
                get 
                {
                    return this.kind; 
                } 
            }
 
            public BindMemberAccessKind MemberAccessKind
            {
                get
                { 
                    return this.accessKind;
                } 
            } 

            internal static string MemberName(string path) 
            {
                string memberName = path;
                //need to show just the latest portion of the path
                int index = memberName.LastIndexOf('.'); 
                memberName = (index != -1 && (index + 1) < memberName.Length) ? memberName.Substring(index + 1) : memberName;
                return memberName; 
            } 
        }
 
        private class ActivityBindFormWorkflowOutline : WorkflowOutline
        {
            private ActivityBindForm parent = null;
            private Activity selectedActivity = null; 
            private PathInfo selectedPathInfo = null;
 
            public ActivityBindFormWorkflowOutline(IServiceProvider serviceProvider, ActivityBindForm parent) 
                : base(serviceProvider)
            { 
                this.parent = parent;
                base.NeedsExpandAll = false;

                this.Expanding += new System.Windows.Forms.TreeViewCancelEventHandler(this.treeView1_BeforeExpand); 

                base.TreeView.BeforeLabelEdit += new NodeLabelEditEventHandler(TreeView_BeforeLabelEdit); 
                base.TreeView.AfterLabelEdit += new NodeLabelEditEventHandler(TreeView_AfterLabelEdit); 
                base.TreeView.LabelEdit = true;
                base.TreeView.KeyDown += new KeyEventHandler(TreeView_KeyDown); 
            }

            void TreeView_KeyDown(object sender, KeyEventArgs e)
            { 
                //F2 -> start editing index
                if (e.KeyCode == Keys.F2 && base.TreeView.SelectedNode != null) 
                { 
                    base.TreeView.SelectedNode.BeginEdit();
                    e.Handled = true; 
                    e.SuppressKeyPress = true;
                }
            }
 
            void TreeView_BeforeLabelEdit(object sender, NodeLabelEditEventArgs e)
            { 
                //allow editing the label only if it's an array member 
                MemberActivityBindTreeNode memberNode = e.Node as MemberActivityBindTreeNode;
                e.CancelEdit = (memberNode == null) || !memberNode.Text.Contains("[") || !memberNode.Text.Contains("]"); 
            }

            void TreeView_AfterLabelEdit(object sender, NodeLabelEditEventArgs e)
            { 
                //
                string oldLabel = e.Node.Text; 
                string newLabel = e.Label; 
                if (oldLabel == null || newLabel == null)
                { 
                    e.CancelEdit = true;
                    return;
                }
 
                MemberActivityBindTreeNode memberNode = e.Node as MemberActivityBindTreeNode;
 
                bool incorrectChange = false; 
                //sanity check (member name has not been changed, still have opening/closing square brackets, same number of commas)
                if (newLabel.IndexOf("[", StringComparison.Ordinal) == -1 || !newLabel.EndsWith("]", StringComparison.Ordinal)) 
                {
                    incorrectChange = true;
                }
                else 
                {
                    string oldMemberName = oldLabel.Substring(0, oldLabel.IndexOf("[", StringComparison.Ordinal)); 
                    string newMemberName = newLabel.Substring(0, newLabel.IndexOf("[", StringComparison.Ordinal)); 
                    incorrectChange = !oldMemberName.Equals(newMemberName, StringComparison.Ordinal);
                } 

                //re-parse, update pathinfo member
                if (!incorrectChange)
                { 
                    ActivityBindTreeNode parentNode = memberNode.Parent as ActivityBindTreeNode;
                    MemberActivityBindTreeNode memberParentNode = parentNode as MemberActivityBindTreeNode; 
                    Type memberType = (memberParentNode != null) ? memberParentNode.PathInfo.PropertyType : this.parent.GetActivityType(parentNode.Activity); 
                    //we will try to parse just the latest member path since the previous is assumed to be valid
                    List reparsedPathInfoList = this.parent.ParseStringPath(memberType, newLabel); 
                    if (reparsedPathInfoList == null || reparsedPathInfoList.Count == 0)
                    {
                        incorrectChange = true;
                    } 
                    else
                    { 
                        PathInfo newPathInfo = reparsedPathInfoList[reparsedPathInfoList.Count - 1];//get the last item in the list 
                        if(newPathInfo.Path.Equals(newLabel, StringComparison.Ordinal))
                            memberNode.PathInfo = newPathInfo; 
                        else
                            incorrectChange = true;
                    }
                } 

                if (incorrectChange) 
                { 
                    DesignerHelpers.ShowError(this.parent.serviceProvider, string.Format(CultureInfo.CurrentCulture, this.parent.IncorrectIndexChange, newLabel));
                    e.CancelEdit = true; 
                }
            }

            private void treeView1_BeforeExpand(object sender, TreeViewCancelEventArgs e) 
            {
                //see if the first child is the dummy node, replace it with members... 
                ActivityBindTreeNode node = e.Node as ActivityBindTreeNode; 
                if (node != null)
                { 
                    if (node.Nodes.Count > 0 && (node.Nodes[0] is DummyActivityBindTreeNode))
                    {
                        //Poluate child members on this node...
                        MemberActivityBindTreeNode memberNode = node as MemberActivityBindTreeNode; 
                        List members = this.parent.PopulateAutoCompleteList(node.Activity, (memberNode != null) ? memberNode.PathInfo : null);
                        List nodes = new List(); 
                        foreach (PathInfo mamberPathInfo in members) 
                        {
                            MemberActivityBindTreeNode childMemberNode = CreateMemberNode(node.Activity, mamberPathInfo); 
                            if (childMemberNode != null)
                            {
                                RefreshNode(childMemberNode, false);
                                nodes.Add(childMemberNode); 
                            }
                        } 
 
                        base.TreeView.BeginUpdate();
                        try 
                        {
                            node.Nodes.RemoveAt(0);
                            e.Node.Nodes.AddRange(nodes.ToArray());
                        } 
                        finally
                        { 
                            base.TreeView.EndUpdate(); 
                        }
                    } 
                }
            }

            public void AddMemberKindImages(ImageList memberTypes) 
            {
                for (int i = 0;i pathInfoList)
            { 
                WorkflowOutlineNode node = base.GetNode(activity);
 
                //now walk all activity children along the property path list 
                if (node != null)
                { 
                    //expand the node to make sure dummy node is populated with the members
                    node.Expand();

                    if (pathInfoList != null && pathInfoList.Count > 0) 
                    {
                        for (int i = 0; i < pathInfoList.Count; i++) 
                        { 
 							//there are several options here - it could be a regular property, an array or an indexer property
							//we'd do couple attempts at trying to find the right node (taking into account the fact that indexes could be changed by the user) 

                            PathInfo currentPathInfo = pathInfoList[i];
                            MemberActivityBindTreeNode matchingChildNode = null;
 
                            //this is an indexer, there could have been a non-indexer before
                            int indexOfOpenBracket = currentPathInfo.Path.IndexOf('['); 
                            if (indexOfOpenBracket != -1) 
                            {
                                string indexPropertyName = currentPathInfo.Path.Substring(0, indexOfOpenBracket); 
                                if (node.Text.Equals(indexPropertyName, StringComparison.Ordinal))
                                {
                                    //need to get back to the parent and select a different child with an index
                                    //see if we need to get the properties on the parent node again... 
                                    if (i > 0 && pathInfoList[i - 1].Path.Equals(indexPropertyName, StringComparison.Ordinal))
                                        node = node.Parent as WorkflowOutlineNode; 
                                } 
                            }
 
                            //find a child node with the same PathInfo member as the given one
                            foreach (TreeNode childNode in node.Nodes)
                            {
                                MemberActivityBindTreeNode memberTreeNode = childNode as MemberActivityBindTreeNode; 
                                if (memberTreeNode != null && memberTreeNode.PathInfo.Equals(currentPathInfo))
                                { 
                                    matchingChildNode = memberTreeNode; 
                                    break;
                                } 

                                //actual indexes may be different from the default ones...
								//if it's a indexer property (this[]), indexes might mismatch
								if (memberTreeNode != null && memberTreeNode.Text.Contains("[") && currentPathInfo.Path.Contains("[")) 
                                {
                                    //need to compare parameter type index collections... 
 									string currentPropertyName = GetMemberNameFromIndexerName(currentPathInfo.Path); 
									string treeNodePropertyName = GetMemberNameFromIndexerName(memberTreeNode.Text);
                                    if (string.Equals(currentPropertyName, treeNodePropertyName, StringComparison.Ordinal) && IsSamePropertyIndexer(currentPathInfo.MemberInfo, memberTreeNode.PathInfo.MemberInfo)) 
                                    {
                                        matchingChildNode = memberTreeNode;
                                        memberTreeNode.PathInfo = currentPathInfo;
                                        memberTreeNode.Text = MemberActivityBindTreeNode.MemberName(currentPathInfo.Path); 
                                        break;
                                    } 
                                } 
                            }
 
                            //havent found matching tree node in the list of children - will exit
                            if (matchingChildNode == null)
                                break;
 
                            node = matchingChildNode;
                            node.Expand(); 
                        } 
                    }
 
                    base.TreeView.SelectedNode = node;

                    System.Windows.Forms.Timer timer = new System.Windows.Forms.Timer();
                    timer.Tick += new EventHandler(timer_Tick); 
                    timer.Interval = 50;
                    timer.Start(); 
                } 
            }
 
 			private string GetMemberNameFromIndexerName(string fullName)
 			{
				int indexOfSeparator = fullName.IndexOf('[');
 				if (indexOfSeparator != -1) 
					fullName = fullName.Substring(0, indexOfSeparator);
				return fullName; 
			} 

            private void timer_Tick(object sender, EventArgs e) 
            {
                System.Windows.Forms.Timer timer = sender as System.Windows.Forms.Timer;
                if (timer != null)
                { 
                    timer.Stop();
                    timer.Tick -= new EventHandler(timer_Tick); 
                } 

                if (base.TreeView.SelectedNode != null) 
                    base.TreeView.SelectedNode.EnsureVisible();

                this.Focus();
            } 

            private bool IsSamePropertyIndexer(MemberInfo member1, MemberInfo member2) 
            { 
                if (member1 == null || member2 == null)
                    return false; 

                PropertyInfo property1 = member1 as PropertyInfo;
                PropertyInfo property2 = member2 as PropertyInfo;
 
                MethodInfo methodInfo1 = member1 as MethodInfo;
                MethodInfo methodInfo2 = member2 as MethodInfo; 
 
                ParameterInfo[] parameters1 = (property1 != null) ? property1.GetIndexParameters() : (methodInfo1 != null) ? methodInfo1.GetParameters() : null;
                ParameterInfo[] parameters2 = (property2 != null) ? property2.GetIndexParameters() : (methodInfo2 != null) ? methodInfo2.GetParameters() : null; 

                if (parameters1 == null || parameters1.Length == 0 || parameters2 == null || parameters2.Length == 0 || parameters1.Length != parameters2.Length)
                    return false;
 
                for (int i = 0; i < parameters1.Length; i++)
                { 
                    if (parameters1[i].ParameterType != parameters2[i].ParameterType) 
                        return false;
                } 

                return true;
            }
 
            public void ExpandRootNode()
            { 
                TreeNode node = base.RootNode; 
                if (node != null)
                { 
                    node.Collapse();
                    node.Expand();
                }
            } 

            public Activity SelectedActivity 
            { 
                get
                { 
                    return this.selectedActivity;
                }
            }
            public PathInfo SelectedMember 
            {
                get 
                { 
                    return this.selectedPathInfo;
                } 
            }
            public string PropertyPath
            {
                get 
                {
                    MemberActivityBindTreeNode memberNode = base.TreeView.SelectedNode as MemberActivityBindTreeNode; 
                    string path = string.Empty; 
                    while (memberNode != null)
                    { 
                        path = (path.Length == 0) ? memberNode.Text : memberNode.Text + "." + path;
                        memberNode = memberNode.Parent as MemberActivityBindTreeNode;
                    }
                    return path; 
                }
            } 
        } 
        #endregion
 
        #region Class PathInfo
        private class PathInfo
        {
            private string path; 
            private MemberInfo memberInfo;
            private Type propertyType; 
 
            public PathInfo(string path, MemberInfo memberInfo, Type propertyType)
            { 
                if (string.IsNullOrEmpty(path))
                    throw new ArgumentNullException("path");
                if (propertyType == null)
                    throw new ArgumentNullException("propertyType"); 
                if (memberInfo == null)
                    throw new ArgumentNullException("memberInfo"); 
 
                this.path = path;
                this.propertyType = propertyType; 
                this.memberInfo = memberInfo;
            }

            public string Path 
            {
                get { return this.path; } 
            } 

            public MemberInfo MemberInfo 
            {
                get { return this.memberInfo; }
            }
 
            public Type PropertyType
            { 
                get { return this.propertyType; } 
            }
 
            //show bind's path information only (no activity id here)
            public override string ToString()
            {
                return this.path; 
            }
 
            public override bool Equals(object obj) 
            {
                PathInfo otherInfo = obj as PathInfo; 
                if (otherInfo == null)
                    return false;

                return this.path.Equals(otherInfo.path, StringComparison.Ordinal); 
            }
 
            public override int GetHashCode() 
            {
                return this.path.GetHashCode(); 
            }
        }
        #endregion
    } 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.

                        

                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK