Bind.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 / Bind.cs / 1305376 / Bind.cs

                            namespace System.Workflow.ComponentModel 
{
    #region Using directives

    using System; 
    using System.IO;
    using System.Xml; 
    using System.Text; 
    using System.CodeDom;
    using System.Reflection; 
    using System.Xml.XPath;
    using System.Collections;
    using System.Xml.Serialization;
    using System.Collections.Generic; 
    using System.ComponentModel;
    using System.Collections.Specialized; 
    using System.ComponentModel.Design; 
    using System.ComponentModel.Design.Serialization;
    using System.Diagnostics; 
    using System.Globalization;
    using System.Drawing.Design;
    using System.Workflow.ComponentModel.Compiler;
    using System.Workflow.ComponentModel.Serialization; 
    using System.Workflow.ComponentModel.Design;
    using System.Configuration; 
    #endregion 

    #region Bind 
 	[Browsable(false)]
	internal abstract class BindBase
    {
		[NonSerialized] 
        protected bool designMode = true;
        [NonSerialized] 
        private object syncRoot = new object(); 

        public abstract object GetRuntimeValue(Activity activity); 
        public abstract object GetRuntimeValue(Activity activity, Type targetType);
		public abstract void SetRuntimeValue(Activity activity, object value);

 		protected virtual void OnRuntimeInitialized(Activity activity) 
		{
 		} 
 	} 

	#endregion 

 	#region Redundant Binds

	#region MemberBind 
	//
 
 	internal abstract class MemberBind : BindBase 
	{
 		private string name = string.Empty; 

 		protected MemberBind()
		{
 		} 

		protected MemberBind(string name) 
		{ 
			this.name = name;
 		} 

		[DefaultValue("")]
 		public string Name
 		{ 
			get
 			{ 
				return this.name; 
			}
		} 

 		internal static object GetValue(MemberInfo memberInfo, object dataContext, string path)
		{
 			if (memberInfo == null) 
 				throw new ArgumentNullException("memberInfo");
			if (dataContext == null) 
 				throw new ArgumentNullException("dataContext"); 
			if (path == null)
				path = string.Empty; 

			if (string.IsNullOrEmpty(path))
 				return null;
 
			object targetObject = dataContext;
 			System.Type memberType = dataContext.GetType(); 
 
 			PathWalker pathWalker = new PathWalker();
			pathWalker.MemberFound += delegate(object sender, PathMemberInfoEventArgs eventArgs) 
 			{
                if (targetObject == null)
                {
                    eventArgs.Action = PathWalkAction.Cancel; 
                    return;
                } 
                switch (eventArgs.MemberKind) 
				{
					case PathMemberKind.Field: 
						memberType = (eventArgs.MemberInfo as FieldInfo).FieldType;
 						targetObject = (eventArgs.MemberInfo as FieldInfo).GetValue(targetObject);
						break;
 
 					case PathMemberKind.Event:
 						EventInfo evt = eventArgs.MemberInfo as EventInfo; 
						memberType = evt.EventHandlerType; 

 						// GetValue() returns the actual value of the property.  We need the Bind object here. 
						// Find out if there is a matching dependency property and get the value throw the DP.
                        DependencyObject dependencyObject = targetObject as DependencyObject;
                        DependencyProperty dependencyProperty = DependencyProperty.FromName(evt.Name, dependencyObject.GetType());
						if (dependencyProperty != null && dependencyObject != null) 
						{
 							if(dependencyObject.IsBindingSet(dependencyProperty)) 
								targetObject = dependencyObject.GetBinding(dependencyProperty); 
 							else
 								targetObject = dependencyObject.GetHandler(dependencyProperty); 
						}
 						else
							targetObject = null;
 
						//
						eventArgs.Action = PathWalkAction.Stop; 
 						break; 

					case PathMemberKind.Property: 
 						memberType = (eventArgs.MemberInfo as PropertyInfo).PropertyType;
 						if (!(eventArgs.MemberInfo as PropertyInfo).CanRead)
						{
 							eventArgs.Action = PathWalkAction.Cancel; 
							return;
						} 
 
						targetObject = (eventArgs.MemberInfo as PropertyInfo).GetValue(targetObject, null);
 						break; 

					case PathMemberKind.IndexedProperty:
 						memberType = (eventArgs.MemberInfo as PropertyInfo).PropertyType;
 						if (!(eventArgs.MemberInfo as PropertyInfo).CanRead) 
						{
 							eventArgs.Action = PathWalkAction.Cancel; 
							return; 
						}
 
						targetObject = (eventArgs.MemberInfo as PropertyInfo).GetValue(targetObject, eventArgs.IndexParameters);
 						break;

					case PathMemberKind.Index:// 
 						memberType = (eventArgs.MemberInfo as PropertyInfo).PropertyType;
 						targetObject = (eventArgs.MemberInfo as PropertyInfo).GetValue(targetObject, BindingFlags.GetProperty, null, eventArgs.IndexParameters, CultureInfo.InvariantCulture); 
						break; 
 				}
                if (targetObject == null) 
                {
                    if (eventArgs.LastMemberInThePath)
                    {
                        eventArgs.Action = PathWalkAction.Cancel; 
                        return;
                    } 
                    else 
                    {
                        throw new InvalidOperationException(SR.GetString(SR.Error_BindPathNullValue, eventArgs.Path)); 
                    }
                }
			};
 
			if (pathWalker.TryWalkPropertyPath(memberType, path))
			{ 
 				//success 
				return ((targetObject != dataContext) ? targetObject : null);
 			} 
 			else
			{
 				//failure
				return null; 
			}
		} 
 
 		internal static void SetValue(object dataContext, string path, object value)
		{ 
 			if (dataContext == null)
 				throw new ArgumentNullException("dataContext");
			if (string.IsNullOrEmpty(path))
 				throw new ArgumentNullException("path"); 

			object parentObj = null; 
			object obj = dataContext; 

			object[] args = null; 
 			MemberInfo memberInfo = null;

			PathWalker pathWalker = new PathWalker();
 			pathWalker.MemberFound += delegate(object sender, PathMemberInfoEventArgs eventArgs) 
 			{
				// 
 				if (obj == null) 
				{
					eventArgs.Action = PathWalkAction.Cancel; 
					return;
 				}

				parentObj = obj; 
 				memberInfo = eventArgs.MemberInfo;
 
 				switch (eventArgs.MemberKind) 
				{
 					case PathMemberKind.Field: 
						obj = (eventArgs.MemberInfo as FieldInfo).GetValue(parentObj);
						args = null;
						break;
 
 					case PathMemberKind.Event:
						// 
 						eventArgs.Action = PathWalkAction.Cancel;//set value is not supported on events 
 						return;
 
					case PathMemberKind.Property:
 						obj = (eventArgs.MemberInfo as PropertyInfo).GetValue(parentObj, null);
						args = null;
						break; 

					case PathMemberKind.IndexedProperty: 
 					case PathMemberKind.Index: 
						obj = (eventArgs.MemberInfo as PropertyInfo).GetValue(parentObj, eventArgs.IndexParameters);
 						args = eventArgs.IndexParameters; 
 						break;
				}
 			};
 
			if (pathWalker.TryWalkPropertyPath(dataContext.GetType(), path))
			{ 
				//at this point the 'obj' holds the old value, we will be changing it to 'value' 
 				//success
				if (memberInfo is FieldInfo) 
 				{
 					(memberInfo as FieldInfo).SetValue(parentObj, value);
				}
 				else if (memberInfo is PropertyInfo) 
				{
                    if ((memberInfo as PropertyInfo).CanWrite) 
                        (memberInfo as PropertyInfo).SetValue(parentObj, value, args); 
                    else
                        throw new InvalidOperationException(SR.GetString(SR.Error_ReadOnlyField, memberInfo.Name)); 
				}
			}
 		}
 
		internal static ValidationError ValidateTypesInPath(Type srcType, string path)
 		{ 
 			ValidationError error = null; 

			if (srcType == null) 
 				throw new ArgumentNullException("srcType");
			if (path == null)
				throw new ArgumentNullException("path");
			if (path.Length == 0) 
 				throw new ArgumentException(SR.GetString(SR.Error_EmptyPathValue), "path");
 
            Debug.Assert(WorkflowCompilationContext.Current != null, "Can't have checkTypes set to true without a context in scope"); 
            IList authorizedTypes = WorkflowCompilationContext.Current.GetAuthorizedTypes();
			if (authorizedTypes == null) 
 			{
 				return new ValidationError(SR.GetString(SR.Error_ConfigFileMissingOrInvalid), ErrorNumbers.Error_ConfigFileMissingOrInvalid);
			}
 
 			Type propertyType = srcType;
			MemberInfo memberInfo = null; 
 
			PathWalker pathWalker = new PathWalker();
			pathWalker.MemberFound += delegate(object sender, PathMemberInfoEventArgs eventArgs) 
 			{
				Type memberType = null;
 				memberInfo = eventArgs.MemberInfo;
 
 				if (memberInfo is FieldInfo)
					memberType = ((FieldInfo)memberInfo).FieldType; 
 
 				if (memberInfo is PropertyInfo)
					memberType = ((PropertyInfo)memberInfo).PropertyType; 

				if (memberType != null && !SafeType(authorizedTypes, memberType))
				{
 					error = new ValidationError(SR.GetString(SR.Error_TypeNotAuthorized, memberType), ErrorNumbers.Error_TypeNotAuthorized); 
					eventArgs.Action = PathWalkAction.Stop;
 					return; 
 				} 
			};
 			pathWalker.TryWalkPropertyPath(propertyType, path); 
			return error;
		}

		private static bool SafeType(IList authorizedTypes, Type referenceType) 
 		{
			bool authorized = false; 
 			foreach (AuthorizedType authorizedType in authorizedTypes) 
 			{
				if (authorizedType.RegularExpression.IsMatch(referenceType.AssemblyQualifiedName)) 
 				{
					authorized = (String.Compare(bool.TrueString, authorizedType.Authorized, StringComparison.OrdinalIgnoreCase) == 0);
					if (!authorized)
					    return false; 
 				}
			} 
            return authorized; 
 		}
 

 		internal static MemberInfo GetMemberInfo(Type srcType, string path)
		{
 			if (srcType == null) 
				throw new ArgumentNullException("srcType");
			if (path == null) 
				throw new ArgumentNullException("path"); 
 			if (path.Length == 0)
				throw new ArgumentException(SR.GetString(SR.Error_EmptyPathValue), "path"); 

 			Type propertyType = srcType;
 			MemberInfo memberInfo = null;
 
			PathWalker pathWalker = new PathWalker();
 			pathWalker.MemberFound += delegate(object sender, PathMemberInfoEventArgs eventArgs) 
			{ 
				memberInfo = eventArgs.MemberInfo;
				if (eventArgs.MemberKind == PathMemberKind.Event) 
 				{
					//need to exit!!!
 					eventArgs.Action = PathWalkAction.Stop;
 					return; 
				}
 			}; 
 
			if (pathWalker.TryWalkPropertyPath(propertyType, path))
				return memberInfo; 
			else
 				return null;
		}
 	} 
 	#endregion
 
	#region FieldBind 
 	[ActivityValidator(typeof(FieldBindValidator))]
	internal sealed class FieldBind : MemberBind 
	{
		private string path = string.Empty;

 		public FieldBind() 
		{
 		} 
 
 		public FieldBind(string name)
			: base(name) 
 		{
		}

		public FieldBind(string name, string path) 
			: base(name)
 		{ 
			this.path = path; 
 		}
 
 		public string Path
		{
 			get
			{ 
				return this.path;
			} 
 			set 
			{
 				if (!this.designMode) 
 					throw new InvalidOperationException(SR.GetString(SR.Error_CanNotChangeAtRuntime));

				this.path = value;
 			} 
		}
 
		public override object GetRuntimeValue(Activity activity, Type targetType) 
		{
 			throw new NotImplementedException(); 
		}

 		public override object GetRuntimeValue(Activity activity)
 		{ 
			throw new NotImplementedException();
 		} 
 
		public override void SetRuntimeValue(Activity activity, object value)
		{ 
			throw new NotImplementedException();
 		}

 
		protected override void OnRuntimeInitialized(Activity activity)
 		{ 
 			throw new NotImplementedException(); 
		}
 	} 

	#endregion

	#region PropertyBind 
	[ActivityValidator(typeof(PropertyBindValidator))]
 	internal sealed class PropertyBind : MemberBind 
	{ 
 		private string path = string.Empty;
 
 		public PropertyBind()
		{
 		}
 
		public PropertyBind(string name)
			: base(name) 
		{ 
 		}
 
		public PropertyBind(string name, string path)
 			: base(name)
 		{
			this.path = path; 
 		}
 
		public string Path 
		{
			get 
 			{
				return this.path;
 			}
 			set 
			{
 				if (!this.designMode) 
					throw new InvalidOperationException(SR.GetString(SR.Error_CanNotChangeAtRuntime)); 

				this.path = value; 
			}
 		}

		public override object GetRuntimeValue(Activity activity, Type targetType) 
 		{
 			throw new NotImplementedException(); 
		} 

 		public override object GetRuntimeValue(Activity activity) 
		{
			throw new NotImplementedException();
		}
 
 		public override void SetRuntimeValue(Activity activity, object value)
		{ 
 			throw new NotImplementedException(); 
 		}
	} 

 	#endregion

	#region MethodBind 
	[ActivityValidator(typeof(MethodBindValidator))]
	internal sealed class MethodBind : MemberBind 
 	{ 
		public MethodBind()
 		{ 
 		}

		public MethodBind(string name)
 			: base(name) 
		{
		} 
 
		public override object GetRuntimeValue(Activity activity, Type targetType)
 		{ 
            throw new NotImplementedException();
		}

 		public override object GetRuntimeValue(Activity activity) 
 		{
			throw new Exception(SR.GetString(SR.Error_NoTargetTypeForMethod)); 
 		} 

		public override void SetRuntimeValue(Activity activity, object value) 
		{
			throw new Exception(SR.GetString(SR.Error_MethodDataSourceIsReadOnly));
 		}
	} 
 	#endregion
 
 	#endregion 

	#region ActivityBind 
    internal enum ActivityBindTypes { Field = 1, Property = 2, Method = 3 };

    [Browsable(true)]
    [TypeConverter(typeof(ActivityBindTypeConverter))] 
 	[ActivityValidator(typeof(ActivityBindValidator))]
    [DesignerSerializer(typeof(BindMarkupExtensionSerializer), typeof(WorkflowMarkupSerializer))] 
	public sealed class ActivityBind : MarkupExtension, IPropertyValueProvider 
	{
		#region stuff from the former Bind 
 		[NonSerialized]
		private bool designMode = true;
        [NonSerialized]
        private bool dynamicUpdateMode = false; 
        [NonSerialized]
 		private IDictionary userData = null; 
 		[NonSerialized] 
		private object syncRoot = new object();
 
 		internal void SetContext(Activity activity)
		{
			this.designMode = false;
			OnRuntimeInitialized(activity); 
 		}
 
        internal bool DynamicUpdateMode 
        {
            get 
            {
                return this.dynamicUpdateMode;
            }
            set 
            {
                this.dynamicUpdateMode = false; 
            } 
        }
 

		[Browsable(false)]
 		[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
 		private bool DesignMode 
		{
 			get 
			{ 
                return this.designMode && !this.dynamicUpdateMode;
			} 
		}

 		[Browsable(false)]
		[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] 
 		public IDictionary UserData
 		{ 
			get 
 			{
				if (this.userData == null) 
				{
					lock (this.syncRoot)
 					{
						if (this.userData == null) 
 							this.userData = Hashtable.Synchronized(new Hashtable());
 					} 
				} 
 				return this.userData;
			} 
		}

		internal static object GetDataSourceObject(Activity activity, string inputName, out string name)
 		{ 
			if (activity == null)
 				throw new ArgumentNullException("activity"); 
 			if (string.IsNullOrEmpty(inputName)) 
				throw new ArgumentNullException("inputName");
 
 			Activity contextActivity = Helpers.GetDataSourceActivity(activity, inputName, out name);
			return contextActivity;
		}
		#endregion 

 		private string id = string.Empty; 
		private string path = string.Empty; 

 		public ActivityBind() 
 		{
		}

        public ActivityBind(string name) 
        {
            this.id = name; 
        } 

 		public ActivityBind(string name, string path) 
		{
			this.id = name;
			this.path = path;
 		} 

		[DefaultValue("")] 
        [SRDescription(SR.ActivityBindIDDescription)] 
        [ConstructorArgument("name")]
        public string Name 
 		{
 			get
			{
 				return this.id; 
			}
			set 
			{ 
 				if (!this.DesignMode)
					throw new InvalidOperationException(SR.GetString(SR.Error_CanNotChangeAtRuntime)); 

 				this.id = value;
 			}
		} 

 		[DefaultValue("")] 
		[SRDescription(SR.ActivityBindPathDescription)] 
        [TypeConverter(typeof(ActivityBindPathTypeConverter))]
		public string Path 
		{
 			get
			{
 				return this.path; 
 			}
			set 
 			{ 
				if (!this.DesignMode)
					throw new InvalidOperationException(SR.GetString(SR.Error_CanNotChangeAtRuntime)); 

				this.path = value;
 			}
		} 

        public override object ProvideValue(IServiceProvider provider) 
        { 
            return this;
        } 

 		public object GetRuntimeValue(Activity activity, Type targetType)
 		{
			if (activity == null) 
 				throw new ArgumentNullException("activity");
			if (targetType == null) 
				throw new ArgumentNullException("targetType"); 
			return this.InternalGetRuntimeValue(activity, targetType);
 		} 

		public object GetRuntimeValue(Activity activity)
 		{
 			if (activity == null) 
				throw new ArgumentNullException("activity");
 			return this.InternalGetRuntimeValue(activity, null); 
		} 

		private object InternalGetRuntimeValue(Activity activity, Type targetType) 
		{
 			object runtimeValue = null;
            Activity referencedActivity = Helpers.ParseActivityForBind(activity, this.Name);
			if (referencedActivity != null) 
 			{
 				//Now lets get the MemberInfo 
				MemberInfo memberInfo = ActivityBind.GetMemberInfo(referencedActivity.GetType(), Path, targetType); 
 				if (memberInfo != null)
				{ 
					runtimeValue = ActivityBind.GetMemberValue(referencedActivity, memberInfo, Path, targetType);
					if (runtimeValue is ActivityBind && BindHelpers.GetMemberType(memberInfo) != typeof(ActivityBind))
 						runtimeValue = ((ActivityBind)runtimeValue).GetRuntimeValue(referencedActivity, targetType);
				} 
                else
                { 
                    // The value of this ActivityBind is bound to properties or events defined on the referenced activity 
                    // Note that we don't have corresponding logic for SetRuntimeValue because value should be only set
                    // at the end of the activity reference chain. 
                    Activity rootActivity = Helpers.GetRootActivity(activity);
                    DependencyProperty dependencyProperty = DependencyProperty.FromName(this.Path, rootActivity.GetType());
                }
 			} 
 			return runtimeValue;
		} 
 
 		public void SetRuntimeValue(Activity activity, object value)
		{ 
			if (activity == null)
				throw new ArgumentNullException("activity");

            Activity referencedActivity = Helpers.ParseActivityForBind(activity, this.Name); 
 			if (referencedActivity != null)
			{ 
 				MemberInfo memberInfo = ActivityBind.GetMemberInfo(referencedActivity.GetType(), Path, null); 
 				if (memberInfo != null)
				{ 
 					ActivityBind bind = ActivityBind.GetMemberValue(referencedActivity, memberInfo, Path, null) as ActivityBind;
					if (bind != null)
						bind.SetRuntimeValue(referencedActivity, value);
					else 
 						MemberBind.SetValue(referencedActivity, this.Path, value);
				} 
 				// Dependency property 
 				/*else
				{ 
 					Activity rootActivity = Helpers.GetRootActivity(activity);
					DependencyProperty dependencyProperty = DependencyProperty.FromName(this.Path, rootActivity.GetType());
					if (dependencyProperty != null)
					{ 
 						referencedActivity.SetValue(dependencyProperty, value);
					} 
 				}*/ 
 			}
		} 

 		private void OnRuntimeInitialized(Activity activity)
		{
			Activity dataSourceActivity = null; 
			ActivityBind activityBind = ActivityBind.GetContextBind(this, activity, out dataSourceActivity);
 			if (activityBind != null && dataSourceActivity != null) 
			{ 
 				Type companionType = dataSourceActivity.GetType();
 				if (companionType != null) 
				{
 					MemberInfo memberInfo = ActivityBind.GetMemberInfo(companionType, activityBind.Path, null);
					if (memberInfo != null)
					{ 
						if (memberInfo is FieldInfo || memberInfo is PropertyInfo || memberInfo is EventInfo)
 						{ 
							if (activityBind.UserData[UserDataKeys.BindDataSource] == null) 
 								activityBind.UserData[UserDataKeys.BindDataSource] = new Hashtable();
 
 							((Hashtable)activityBind.UserData[UserDataKeys.BindDataSource])[activity.QualifiedName] = memberInfo;
							if (dataSourceActivity != null)
 							{
								if (activityBind.UserData[UserDataKeys.BindDataContextActivity] == null) 
									activityBind.UserData[UserDataKeys.BindDataContextActivity] = new Hashtable();
								((Hashtable)activityBind.UserData[UserDataKeys.BindDataContextActivity])[activity.QualifiedName] = dataSourceActivity.QualifiedName; 
 							} 
						}
 					} 
 					/*else
					{
 						Activity rootActivity = Helpers.GetRootActivity(activity);
						DependencyProperty dependencyProperty = DependencyProperty.FromName(activityBind.Path, rootActivity.GetType()); 
						if (dependencyProperty != null)
						{ 
 							if (activityBind.UserData[UserDataKeys.BindDataSource] == null) 
								activityBind.UserData[UserDataKeys.BindDataSource] = new Hashtable();
 
 							((Hashtable)activityBind.UserData[UserDataKeys.BindDataSource])[activity.QualifiedName] = dependencyProperty;

 							if (dataSourceActivity != null)
							{ 
 								if (activityBind.UserData[UserDataKeys.BindDataContextActivity] == null)
									activityBind.UserData[UserDataKeys.BindDataContextActivity] = new Hashtable(); 
								((Hashtable)activityBind.UserData[UserDataKeys.BindDataContextActivity])[activity.QualifiedName] = dataSourceActivity.QualifiedName; 
							}
 						} 
					}*/
 				}
 			}
		} 

 		public override string ToString() 
		{ 
            Activity activity = UserData[UserDataKeys.BindDataContextActivity] as Activity;
            if (activity != null) 
            {
                string bindString = String.Empty;
                if (!string.IsNullOrEmpty(Name))
                    bindString = Helpers.ParseActivityForBind(activity, Name).QualifiedName; 

                if (!string.IsNullOrEmpty(Path)) 
                { 
                    string path = Path;
                    int indexOfSeparator = path.IndexOfAny(new char[] { '.', '/', '[' }); 
                    path = ((indexOfSeparator != -1)) ? path.Substring(0, indexOfSeparator) : path;
                    bindString += (!String.IsNullOrEmpty(bindString)) ? "." + path : path;
                }
 
                return bindString;
            } 
            else 
            {
                return base.ToString(); 
            }
        }

        #region Runtime / Validation Time Helpers 
        internal static MemberInfo GetMemberInfo(Type dataSourceType, string path, Type targetType)
		{ 
			MemberInfo memberInfo = MemberBind.GetMemberInfo(dataSourceType, path); 

 			//The events can be either bound to properties or can be bound to methods, 
			//There are cases where fields and methods can be of same name so in that case we either make sure for
 			//in the case of event handlers we either find Property or a Method
            if (targetType != null && typeof(Delegate).IsAssignableFrom(targetType) && (memberInfo == null || !(memberInfo is EventInfo)))
            { 
 				MethodInfo delegateMethod = targetType.GetMethod("Invoke");
				List paramTypes = new List(); 
 				foreach (ParameterInfo paramInfo in delegateMethod.GetParameters()) 
					paramTypes.Add(paramInfo.ParameterType);
 
				memberInfo = dataSourceType.GetMethod(path, BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.FlattenHierarchy, null, paramTypes.ToArray(), null);
			}

 			return memberInfo; 
		}
 
 		private static object GetMemberValue(object dataSourceObject, MemberInfo memberInfo, string path, Type targetType) 
 		{
			object memberValue = null; 
 			if (memberInfo is FieldInfo || memberInfo is PropertyInfo || memberInfo is EventInfo)
			{
				memberValue = MemberBind.GetValue(memberInfo, dataSourceObject, path);
				 
 				/*if (memberValue != null && targetType != null &&
					(memberValue.GetType().IsPrimitive || memberValue.GetType().IsEnum || memberValue.GetType() == typeof(string)) 
 					&& !targetType.IsAssignableFrom(memberValue.GetType())) 
 				{
					try 
 					{
						memberValue = Convert.ChangeType(memberValue, targetType, CultureInfo.InvariantCulture);
					}
					catch (Exception e) 
 					{
						throw new Exception(SR.GetString(SR.Error_DataSourceTypeConversionFailed, memberInfo.Name, memberValue.ToString(), targetType.FullName), e); 
 					} 
 				}*/
			} 
 			else if (targetType != null && memberInfo is MethodInfo)
			{
				memberValue = Delegate.CreateDelegate(targetType, dataSourceObject, (MethodInfo)memberInfo);//the wrapper method will never be static (even if the original one is)
			} 
 			else
			{ 
 				throw new InvalidOperationException(SR.GetString(SR.Error_MemberNotFound)); 
 			}
 
			return memberValue;
 		}

		//This function is used to get the outermost activity bind which is bound to actual field/property 
        //The function is called in OnRuntimeInitialized and makes sure that we get outer target bind and cache
        //it so that at runtime we do not have to walk the bind chain to find the bound member 
		private static ActivityBind GetContextBind(ActivityBind activityBind, Activity activity, out Activity contextActivity) 
		{
 			if (activityBind == null) 
				throw new ArgumentNullException("activityBind");
 			if (activity == null)
 				throw new ArgumentNullException("activity");
 
			BindRecursionContext recursionContext = new BindRecursionContext();
 			ActivityBind contextBind = activityBind; 
			contextActivity = activity; 
			
			while (contextBind != null) 
 			{
                Activity resolvedActivity = Helpers.ParseActivityForBind(contextActivity, contextBind.Name);
				if (resolvedActivity == null)
 					return null; 

 				object dataSourceObject = resolvedActivity; 
				MemberInfo memberInfo = ActivityBind.GetMemberInfo(dataSourceObject.GetType(), contextBind.Path, null); 
 				if (memberInfo == null)
				{ 
					contextActivity = resolvedActivity;
					return contextBind;
 				}
				else if (memberInfo is FieldInfo) 
 				{
 					contextActivity = resolvedActivity; 
					return contextBind; 
 				}
				else if(memberInfo is PropertyInfo && (memberInfo as PropertyInfo).PropertyType == typeof(ActivityBind) && dataSourceObject != null) 
				{
					object value = MemberBind.GetValue(memberInfo, dataSourceObject, contextBind.Path);
 					if (value is ActivityBind)
					{ 
 						if (recursionContext.Contains(contextActivity, contextBind))
 							return null; 
 
						recursionContext.Add(contextActivity, contextBind);
 						contextActivity = resolvedActivity; 
						contextBind = value as ActivityBind;
					}
					else
 					{ 
						return null;
 					} 
 				} 
				else
 				{ 
					return null;
				}
			}
 			return contextBind; 
        }
        #endregion 
 
        #region DesignTime Integration (DO NOT CALL THESE AT RUNTIME)
 
        #region Helper Functions
        // This function replaces Activity1.code1 with /ParentContext.code1.  This must be done for Binds that refer to
        // to fields, properties and methods in the top level custom activity data context.
        internal static string GetRelativePathExpression(Activity parentActivity, Activity childActivity) 
        {
            string relativeBindExpression = String.Empty; 
 
            Activity rootActivity = Helpers.GetRootActivity(childActivity);
            if (rootActivity == childActivity) 
                relativeBindExpression = "/Self";
            else
                relativeBindExpression = parentActivity.QualifiedName;
 
            return relativeBindExpression;
        } 
 
        #region IPropertyValueProvider Implementation
        ICollection IPropertyValueProvider.GetPropertyValues(ITypeDescriptorContext context) 
        {
            ArrayList values = new ArrayList();

            if (string.Equals(context.PropertyDescriptor.Name, "Path", StringComparison.Ordinal) && !String.IsNullOrEmpty(Name) && context.PropertyDescriptor is ActivityBindPathPropertyDescriptor) 
            {
                ITypeDescriptorContext outerPropertyContext = ((ActivityBindPathPropertyDescriptor)context.PropertyDescriptor).OuterPropertyContext; 
                if (outerPropertyContext != null) 
                {
                    Activity activity = PropertyDescriptorUtils.GetComponent(outerPropertyContext) as Activity; 
                    if (activity != null)
                    {
                        Activity targetActivity = Helpers.ParseActivityForBind(activity, Name);
                        if (targetActivity != null) 
                        {
                            foreach (MemberInfo memberInfo in ActivityBindPropertyDescriptor.GetBindableMembers(targetActivity, outerPropertyContext)) 
                                values.Add(memberInfo.Name); 
                        }
                    } 
                }
            }

            return values; 
        }
        #endregion 
 
        #endregion
 
        #endregion
    }
    #endregion
 
	#region BindRecursionContext
 
 	internal sealed class BindRecursionContext 
 	{
		private Hashtable activityBinds = new Hashtable(); 

 		public bool Contains(Activity activity, ActivityBind bind)
		{
			if (activity == null) 
				throw new ArgumentNullException("activity");
 			if (bind == null) 
				throw new ArgumentNullException("bind"); 

 			if (this.activityBinds[activity] != null) 
 			{
				List binds = this.activityBinds[activity] as List;
 				foreach (ActivityBind prevBind in binds)
				{ 
					if (prevBind.Path == bind.Path)
						return true; 
 				} 
			}
 			return false; 
 		}

		public void Add(Activity activity, ActivityBind bind)
 		{ 
			if (activity == null)
				throw new ArgumentNullException("activity"); 
			if (bind == null) 
 				throw new ArgumentNullException("bind");
			if (this.activityBinds[activity] == null) 
 				this.activityBinds[activity] = new List();

 			((List)this.activityBinds[activity]).Add(bind);
		} 
 	}
 
	#endregion 

	#region BindHelpers 
	internal static class BindHelpers
 	{
		internal static Type GetBaseType(IServiceProvider serviceProvider, PropertyValidationContext validationContext)
 		{ 
 			Type type = null;
			if (validationContext.Property is PropertyInfo) 
 			{ 
				type = Helpers.GetBaseType(validationContext.Property as PropertyInfo, validationContext.PropertyOwner, serviceProvider);
			} 
			else if (validationContext.Property is DependencyProperty)
 			{
				//
 				DependencyProperty dependencyProperty = validationContext.Property as DependencyProperty; 
 				if (dependencyProperty != null)
				{ 
 					if (type == null) 
					{
						IDynamicPropertyTypeProvider basetypeProvider = validationContext.PropertyOwner as IDynamicPropertyTypeProvider; 
						if (basetypeProvider != null)
                            type = basetypeProvider.GetPropertyType(serviceProvider, dependencyProperty.Name);
 					}
 
					if (type == null)
 						type = dependencyProperty.PropertyType; 
 				} 
			}
 
 			return type;
		}

		internal static AccessTypes GetAccessType(IServiceProvider serviceProvider, PropertyValidationContext validationContext) 
		{
 			AccessTypes accessType = AccessTypes.Read; 
			if (validationContext.Property is PropertyInfo) 
 			{
 				accessType = Helpers.GetAccessType(validationContext.Property as PropertyInfo, validationContext.PropertyOwner, serviceProvider); 
			}
 			else if (validationContext.Property is DependencyProperty)
			{
				IDynamicPropertyTypeProvider basetypeProvider = validationContext.PropertyOwner as IDynamicPropertyTypeProvider; 
				if (basetypeProvider != null)
                    accessType = basetypeProvider.GetAccessType(serviceProvider, ((DependencyProperty)validationContext.Property).Name); 
 			} 

			return accessType; 
 		}

 		internal static object ResolveActivityPath(Activity refActivity, string path)
		{ 
 			if (refActivity == null)
				throw new ArgumentNullException("refActivity"); 
			if (path == null) 
				throw new ArgumentNullException("path");
 			if (path.Length == 0) 
                throw new ArgumentException(SR.GetString(SR.Error_EmptyPathValue), "path");

			object value = refActivity;
 			BindRecursionContext recursionContext = new BindRecursionContext(); 

 			PathWalker pathWalker = new PathWalker(); 
			pathWalker.MemberFound += delegate(object sender, PathMemberInfoEventArgs eventArgs) 
 			{
				// If value is null, we don't want to use GetValue on the MemberInfo 
				if (value == null)
				{
 					eventArgs.Action = PathWalkAction.Cancel;//need to cancel the walk with the failure return result
					return; 
 				}
 
 				switch (eventArgs.MemberKind) 
				{
 					case PathMemberKind.Field: 
						try
						{
							value = (eventArgs.MemberInfo as FieldInfo).GetValue(value);
 						} 
						catch(Exception exception)
 						{ 
 							//in some cases the value might not be there yet (e.g. validation vs. runtime) 
							value = null;
 							eventArgs.Action = PathWalkAction.Cancel; 

							//we should throw only if we are at the runtime
							if (!refActivity.DesignMode)
							{ 
 								TargetInvocationException targetInvocationException = exception as TargetInvocationException;
								throw (targetInvocationException != null) ? targetInvocationException.InnerException : exception; 
 							} 
 						}
						break; 

 					case PathMemberKind.Event:
						EventInfo evt = eventArgs.MemberInfo as EventInfo;
 
						// GetValue() returns the actual value of the property.  We need the Bind object here.
						// Find out if there is a matching dependency property and get the value throw the DP. 
 						DependencyProperty eventDependencyProperty = DependencyProperty.FromName(evt.Name, value.GetType()); 
						if (eventDependencyProperty != null && value is DependencyObject)
 						{ 
 							if ((value as DependencyObject).IsBindingSet(eventDependencyProperty))
								value = (value as DependencyObject).GetBinding(eventDependencyProperty);
 							else
                                value = (value as DependencyObject).GetHandler(eventDependencyProperty); 
						}
						break; 
 
					case PathMemberKind.Property:
 						if (!(eventArgs.MemberInfo as PropertyInfo).CanRead) 
						{
 							eventArgs.Action = PathWalkAction.Cancel;
 							return;
						} 

 						// GetValue() returns the actual value of the property.  We need the Bind object here. 
						// Find out if there is a matching dependency property and get the value throw the DP. 
						DependencyProperty dependencyProperty = DependencyProperty.FromName(eventArgs.MemberInfo.Name, value.GetType());
                        if (dependencyProperty != null && value is DependencyObject && (value as DependencyObject).IsBindingSet(dependencyProperty)) 
                            value = (value as DependencyObject).GetBinding(dependencyProperty);
						else
 							try
							{ 
 								value = (eventArgs.MemberInfo as PropertyInfo).GetValue(value, null);
 							} 
							catch(Exception exception) 
 							{
								//property getter function might throw at design time, validation should not fail bacause of that 
								value = null;
								eventArgs.Action = PathWalkAction.Cancel;

 								//we should throw only if we are at the runtime 
								if (!refActivity.DesignMode)
 								{ 
 									TargetInvocationException targetInvocationException = exception as TargetInvocationException; 
									throw (targetInvocationException != null) ? targetInvocationException.InnerException : exception;
 								} 
							}
						break;

					case PathMemberKind.IndexedProperty: 
 					case PathMemberKind.Index:
						try 
 						{ 
 							value = (eventArgs.MemberInfo as PropertyInfo).GetValue(value, BindingFlags.GetProperty, null, eventArgs.IndexParameters, CultureInfo.InvariantCulture);
						} 
 						catch(Exception exception)
						{
							//in some cases the value might not be there yet - e.g. array or dictionary is populated at runtime only (validation vs. runtime)
							value = null; 
 							eventArgs.Action = PathWalkAction.Cancel;
							 
 							//we should throw only if we are at the runtime 
 							if (!refActivity.DesignMode)
							{ 
 								TargetInvocationException targetInvocationException = exception as TargetInvocationException;
								throw (targetInvocationException != null) ? targetInvocationException.InnerException : exception;
							}
						} 
 						break;
				} 
 
 				//need to unwrap the activity bind if we get one - to proceed with the actual field/property/delegate
 				//do not unwrap if the property/field is itself of type ActivityBind 
				//we should not unwrap the latest ActivityBind though - only intermediate ones
 				//avoid circular reference problems with the BindRecursionContext
				if (value is ActivityBind && !eventArgs.LastMemberInThePath && GetMemberType(eventArgs.MemberInfo) != typeof(ActivityBind))
				{ 
					while (value is ActivityBind)
 					{ 
						ActivityBind activityBind = value as ActivityBind; 
 						if (recursionContext.Contains(refActivity, activityBind))
 							throw new InvalidOperationException(SR.GetString(SR.Bind_ActivityDataSourceRecursionDetected)); 

						recursionContext.Add(refActivity, activityBind);
 						value = activityBind.GetRuntimeValue(refActivity);
					} 
				}
			}; 
 
 			if (pathWalker.TryWalkPropertyPath(refActivity.GetType(), path))
				return value; 
 			else
 				return null;
		}
 
 		internal static PropertyInfo GetMatchedPropertyInfo(Type memberType, string[] aryArgName, object[] args)
		{ 
			if (memberType == null) 
				throw new ArgumentNullException("memberType");
 			if (aryArgName == null) 
				throw new ArgumentNullException("aryArgName");
 			if (args == null)
 				throw new ArgumentNullException("args");
 
			MemberInfo[][] aryMembers = new MemberInfo[][] { memberType.GetDefaultMembers(), null };
 
            if (memberType.IsArray) 
            {
                MemberInfo[] getMember = memberType.GetMember("Get");//arrays will always implement that 
                MemberInfo[] setMember = memberType.GetMember("Set");//arrays will always implement that
                PropertyInfo getProperty = new ActivityBindPropertyInfo(memberType, getMember[0] as MethodInfo, setMember[0] as MethodInfo, string.Empty, null);
                aryMembers[1] = new MemberInfo[] { getProperty };
            } 

 			for (int index = 0; index < aryMembers.Length; ++index) 
			{ 
				if (aryMembers[index] == null)
					continue; 
 				MemberInfo[] defaultMembers = aryMembers[index];
				foreach (MemberInfo memberInfo in defaultMembers)
 				{
                    PropertyInfo propertyInfo = memberInfo as PropertyInfo; 
                    if (propertyInfo != null)
 					{ 
                        if (MatchIndexerParameters(propertyInfo, aryArgName, args)) 
                            return propertyInfo;
					} 
 				}
			}
			return null;
 
		}
 
        internal static bool MatchIndexerParameters(PropertyInfo propertyInfo, string[] argNames, object[] args) 
 		{
            if (propertyInfo == null) 
                throw new ArgumentNullException("propertyInfo");
			if (argNames == null)
 				throw new ArgumentNullException("argNames");
 			if (args == null) 
				throw new ArgumentNullException("args");
 
 			ParameterInfo[] aryPI = propertyInfo.GetIndexParameters(); 
			if (aryPI.Length != argNames.Length)
				return false; 

			for (int index = 0; index < args.Length; ++index)
 			{
				Type paramType = aryPI[index].ParameterType; 
 				if (paramType != typeof(String) && paramType != typeof(System.Int32))
 					return false; 
				try 
 				{
					object arg = null; 
					string argName = argNames[index].Trim();
					if (paramType == typeof(String) && argName.StartsWith("\"", StringComparison.Ordinal) && argName.EndsWith("\"", StringComparison.Ordinal))
 						arg = argName.Substring(1, argName.Length - 2).Trim();
					else if (paramType == typeof(System.Int32)) 
 						arg = Convert.ChangeType(argName, typeof(System.Int32), CultureInfo.InvariantCulture);
 
 					if (arg != null) 
						args.SetValue(arg, index);
 					else 
						return false;
				}
				catch
 				{ 
					return false;
 				} 
 			} 
			return true;
 		} 

		internal static Type GetMemberType(MemberInfo memberInfo)
		{
			FieldInfo fieldInfo = memberInfo as FieldInfo; 
 			if (fieldInfo != null)
				return fieldInfo.FieldType; 
 
 			PropertyInfo propertyInfo = memberInfo as PropertyInfo;
 			if (propertyInfo != null) 
			{
 				if (propertyInfo.PropertyType != null)
					return propertyInfo.PropertyType;
 
				//sometimes need to get the property type off the getter method
				MethodInfo getter = propertyInfo.GetGetMethod(); 
 				return getter.ReturnType; 
			}
 
 			EventInfo eventInfo = memberInfo as EventInfo;
 			if (eventInfo != null)
				return eventInfo.EventHandlerType;
 
 			return null;
		} 
    } 

	#endregion 

	#region Class PathWalker
 	internal enum PathMemberKind { Field, Event, Property, IndexedProperty, Index }
	internal enum PathWalkAction { Continue, Stop, Cancel };//stop returns true, while cancel returns false 

 	internal class PathMemberInfoEventArgs : EventArgs 
 	{ 
		private string path;
 		private Type parentType; 
		private PathMemberKind memberKind;
		private MemberInfo memberInfo;
		private object[] indexParameters = new object[0];//not empty for IndexedProperty and Index types
 		private PathWalkAction action = PathWalkAction.Continue; 
		private bool lastMemberInThePath = false;
 
 		public PathMemberInfoEventArgs(string path, Type parentType, MemberInfo memberInfo, PathMemberKind memberKind, bool lastMemberInThePath) 
 		{
			if (string.IsNullOrEmpty(path)) 
 				throw new ArgumentNullException("path");
			if (parentType == null)
				throw new ArgumentNullException("parentType");
			if (memberInfo == null) 
 				throw new ArgumentNullException("memberInfo");
 
			this.path = path; 
 			this.parentType = parentType;
 			this.memberInfo = memberInfo; 
			this.memberKind = memberKind;
 			this.lastMemberInThePath = lastMemberInThePath;
		}
 
		public PathMemberInfoEventArgs(string path, Type parentType, MemberInfo memberInfo, PathMemberKind memberKind, bool lastMemberInThePath, object[] indexParameters)
			: this(path, parentType, memberInfo, memberKind, lastMemberInThePath) 
 		{ 
			this.indexParameters = indexParameters;
 		} 

 		public string Path
		{
 			get { return this.path; } 
		}
		//public Type ParentType 
		//{ 
 		//    get { return this.parentType; }
		//} 
 		public MemberInfo MemberInfo
 		{
			get { return this.memberInfo; }
 		} 
		public PathMemberKind MemberKind
		{ 
			get { return this.memberKind; } 
 		}
		public object[] IndexParameters 
 		{
 			get { return this.indexParameters; }
		}
 		public bool LastMemberInThePath 
		{
			get { return this.lastMemberInThePath; } 
		} 
 		public PathWalkAction Action
		{ 
 			get { return this.action; }
 			set { this.action = value; }
		}
 	} 

	internal class PathErrorInfoEventArgs : EventArgs 
	{ 
		private SourceValueInfo info;
 		private string currentPath; 

		public PathErrorInfoEventArgs(SourceValueInfo info, string currentPath)
 		{
 			if (currentPath == null) 
				throw new ArgumentNullException("currentPath");
 
 			this.info = info; 
			this.currentPath = currentPath;
		} 

		//public SourceValueInfo Info
 		//{
		//    get { return this.info; } 
 		//}
 		//public string CurrentPath 
		//{ 
 		//    get { return this.currentPath; }
		//} 
	}

	//common path walker
 	//it is based off the property types and the PathParser results 
	//caller might keep a ref to the actual object and call Get/Set value on the members returned in the PathMemberInfoEventArgs
 	internal class PathWalker 
 	{ 
		public EventHandler MemberFound;//on every member along the path
 		public EventHandler PathErrorFound;//if there was an error parsing or walking the path 

		private static MemberInfo[] PopulateMembers(Type type, string memberName)
		{
			List members = new List(); 
 			members.AddRange(type.GetMember(memberName, MemberTypes.Field | MemberTypes.Property | MemberTypes.Event | MemberTypes.Method, BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance | BindingFlags.FlattenHierarchy));
 
			if (type.IsInterface) 
 			{
 				Type[] interfaces = type.GetInterfaces(); 
				foreach (Type implementedInterface in interfaces)
 				{
					members.AddRange(implementedInterface.GetMember(memberName, MemberTypes.Field | MemberTypes.Property | MemberTypes.Event | MemberTypes.Method, BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance | BindingFlags.FlattenHierarchy));
				} 
			}
 
 			return members.ToArray(); 
		}
 
 		public bool TryWalkPropertyPath(Type rootType, string path)
 		{
			if (rootType == null)
 				throw new ArgumentNullException("rootType"); 
			if (string.IsNullOrEmpty(path))
				throw new ArgumentNullException("path"); 
 
			Type propertyType = rootType;
 			string currentPath = string.Empty; 

			PathParser parser = new PathParser();
 			List pathInfo = parser.Parse(path, true);
 			string parsingError = parser.Error; 

			for (int i = 0; i < pathInfo.Count; i++) 
 			{ 
				SourceValueInfo info = pathInfo[i];
 
				if (string.IsNullOrEmpty(info.name))
				{
 					if (PathErrorFound != null)
						PathErrorFound(this, new PathErrorInfoEventArgs(info, currentPath)); 
 					
 					return false; 
				} 

 				string additionalPath = (info.type == SourceValueType.Property) ? info.name : "[" + info.name + "]"; 
				string newPath = (string.IsNullOrEmpty(currentPath)) ? additionalPath : currentPath + ((info.type == SourceValueType.Property) ? "." : string.Empty) + additionalPath;

				Type newPropertyType = null;
				MemberInfo newMemberInfo = null; 

 				switch (info.type) 
				{ 
 					case SourceValueType.Property:
 						MemberInfo[] members = PopulateMembers(propertyType, info.name); 
						if (members == null || members.Length == 0 || members[0] == null)
 						{
							if (PathErrorFound != null)
								PathErrorFound(this, new PathErrorInfoEventArgs(info, currentPath)); 
					
 							return false; 
						} 

 						newMemberInfo = members[0]; 
                        if (newMemberInfo is EventInfo || newMemberInfo is MethodInfo)
 						{
							if(MemberFound != null)
 							{ 
								PathMemberInfoEventArgs args = new PathMemberInfoEventArgs(newPath, propertyType, newMemberInfo, PathMemberKind.Event, i == pathInfo.Count - 1);
								MemberFound(this, args); 
 
								if (args.Action == PathWalkAction.Cancel)
 									return false; 
								else if (args.Action == PathWalkAction.Stop)
 									return true;
 							}
							 
 							//
							return string.IsNullOrEmpty(parsingError); 
						} 
						else if (newMemberInfo is PropertyInfo)
 						{ 
							//property getter could be an indexer
 							PropertyInfo memberPropertyInfo = newMemberInfo as PropertyInfo;
 							MethodInfo getterMethod = memberPropertyInfo.GetGetMethod();
							MethodInfo setterMethod = memberPropertyInfo.GetSetMethod(); 
 							ActivityBindPropertyInfo properyInfo = new ActivityBindPropertyInfo(propertyType, getterMethod, setterMethod, memberPropertyInfo.Name, memberPropertyInfo);
 
							newPropertyType = properyInfo.PropertyType; 
							ParameterInfo[] parameters = properyInfo.GetIndexParameters();
							if (parameters.Length > 0) 
 							{
								//need to check that the next parsed element is an indexer
 								if (i < pathInfo.Count - 1 && pathInfo[i + 1].type == SourceValueType.Indexer && !string.IsNullOrEmpty(pathInfo[i + 1].name))
 								{ 
									string[] arrayArgName = pathInfo[i + 1].name.Split(',');
 									object[] arguments = new object[arrayArgName.Length]; 
 
									//match the number/type of parameters from the following indexer item
									if (BindHelpers.MatchIndexerParameters(properyInfo, arrayArgName, arguments)) 
									{
 										newPath += "[" + pathInfo[i + 1].name + "]";
										
 										//indexer property, uses two of the parsed array elements 
 										if(MemberFound != null)
										{ 
 											PathMemberInfoEventArgs args = new PathMemberInfoEventArgs(newPath, propertyType, properyInfo, PathMemberKind.IndexedProperty, i == pathInfo.Count - 2, arguments); 
											MemberFound(this, args);
 
											if (args.Action == PathWalkAction.Cancel)
												return false;
 											else if (args.Action == PathWalkAction.Stop)
												return true; 
 										}
 
 										//skip the next indexer item too 
										i++;
 									} 
									else
									{
										//parameters didn't match
 										if (PathErrorFound != null) 
											PathErrorFound(this, new PathErrorInfoEventArgs(info, currentPath));
 										 
 										return false; 
									}
 								} 
								else
								{
									//trailing index is missing or empty for the indexed property
 									if (PathErrorFound != null) 
										PathErrorFound(this, new PathErrorInfoEventArgs(info, currentPath));
 										 
 									return false; 
								}
 							} 
							else // parameters.Length == 0
							{
								//a regular property
 								if(MemberFound != null) 
								{
 									PathMemberInfoEventArgs args = new PathMemberInfoEventArgs(newPath, propertyType, properyInfo, PathMemberKind.Property, i == pathInfo.Count - 1); 
 									MemberFound(this, args); 
									
 									if (args.Action == PathWalkAction.Cancel) 
										return false;
									else if (args.Action == PathWalkAction.Stop)
										return true;
 								} 
							}
 						} 
 						else 
						{
 							//that would be a field 
							if(MemberFound != null)
							{
								PathMemberInfoEventArgs args = new PathMemberInfoEventArgs(newPath, propertyType, newMemberInfo, PathMemberKind.Field, i == pathInfo.Count - 1);
 								MemberFound(this, args); 

								if (args.Action == PathWalkAction.Cancel) 
 									return false; 
 								else if (args.Action == PathWalkAction.Stop)
									return true; 
 							}

							newPropertyType = (newMemberInfo as FieldInfo).FieldType;
						} 

						break; 
 
 					case SourceValueType.Indexer:
						if (!string.IsNullOrEmpty(info.name)) 
 						{
 							string[] arrayArgName = info.name.Split(',');
							object[] arguments = new object[arrayArgName.Length];
 
 							PropertyInfo arrayPropertyInfo = BindHelpers.GetMatchedPropertyInfo(propertyType, arrayArgName, arguments);
							if(arrayPropertyInfo != null) 
							{ 
								if(MemberFound != null)
 								{ 
									PathMemberInfoEventArgs args = new PathMemberInfoEventArgs(newPath, propertyType, arrayPropertyInfo, PathMemberKind.Index, i == pathInfo.Count - 1, arguments);
 									MemberFound(this, args);

 									if (args.Action == PathWalkAction.Cancel) 
										return false;
 									else if (args.Action == PathWalkAction.Stop) 
										return true; 
								}
 
								newPropertyType = arrayPropertyInfo.PropertyType;
 								if(newPropertyType == null)
									newPropertyType = arrayPropertyInfo.GetGetMethod().ReturnType;
 							} 
 							else
							{ 
 								//did not mach number/type of arguments 
								if (PathErrorFound != null)
									PathErrorFound(this, new PathErrorInfoEventArgs(info, currentPath)); 
								
 								return false;
							}
 						} 
 						else
						{ 
 							//empty indexer 
							if (PathErrorFound != null)
								PathErrorFound(this, new PathErrorInfoEventArgs(info, currentPath)); 
										
 							return false;
						}
 
 						break;
 				} 
 
				propertyType = newPropertyType;
 				currentPath = newPath; 
			}

			return string.IsNullOrEmpty(parsingError);
		} 
 	}
 
	//multi-dimentional arrays dont implement default property 
 	//this fake property will help us to handle that
 	internal class ActivityBindPropertyInfo : PropertyInfo 
	{
 		private MethodInfo getMethod;
		private MethodInfo setMethod;
		private Type declaringType; 
		private string propertyName;
 		private PropertyInfo originalPropertyInfo;//in vb fields get returned as properties 
 
		public ActivityBindPropertyInfo(Type declaringType, MethodInfo getMethod, MethodInfo setMethod, string propertyName, PropertyInfo originalPropertyInfo)
 		{ 
 			if (declaringType == null)
				throw new ArgumentNullException("declaringType");
 			if (propertyName == null)
				throw new ArgumentNullException("propertyName"); 

			this.declaringType = declaringType; 
			this.getMethod = getMethod; 
 			this.setMethod = setMethod;
			this.propertyName = propertyName; 
 			this.originalPropertyInfo = originalPropertyInfo;//could be null for array indexers.
 		}

		public override string Name 
 		{
			get { return this.propertyName; } 
		} 

		public override MethodInfo GetGetMethod(bool nonPublic) 
 		{
			return this.getMethod;
 		}
 
 		public override MethodInfo GetSetMethod(bool nonPublic)
		{ 
 			return this.setMethod; 
		}
 
		public override Type PropertyType
		{
 			get
			{ 
 				if (this.getMethod != null)
 					return this.getMethod.ReturnType; 
				else if (this.originalPropertyInfo != null) 
 					return this.originalPropertyInfo.PropertyType;
				else 
					return typeof(object);
			}
 		}
 
		public override ParameterInfo[] GetIndexParameters()
 		{ 
 			if (this.getMethod != null) 
				return this.getMethod.GetParameters();
 			else if (this.originalPropertyInfo != null) 
				return this.originalPropertyInfo.GetIndexParameters();
			else
				return new ParameterInfo[0];
 		} 

		public override object GetValue(object obj, BindingFlags invokeAttr, Binder binder, object[] index, CultureInfo culture) 
 		{ 
 			if (this.getMethod == null && (this.originalPropertyInfo == null || !this.originalPropertyInfo.CanRead))
				throw new InvalidOperationException(SR.GetString(SR.Error_PropertyHasNoGetterDefined, this.propertyName)); 

 			if (this.getMethod != null)
				return this.getMethod.Invoke(obj, invokeAttr, binder, index, culture);
			else 
				return this.originalPropertyInfo.GetValue(obj, invokeAttr, binder, index, culture);
 		} 
 
		public override void SetValue(object obj, object value, BindingFlags invokeAttr, Binder binder, object[] index, CultureInfo culture)
 		{ 
 			if (this.setMethod == null && (this.originalPropertyInfo == null || !this.originalPropertyInfo.CanWrite))
				throw new InvalidOperationException(SR.GetString(SR.Error_PropertyHasNoSetterDefined, this.propertyName));

 			if (this.setMethod != null) 
			{
				object[] parameters = new object[((index != null) ? index.Length : 0) + 1]; 
				parameters[((index != null) ? index.Length : 0)] = value; 

 				if (index != null) 
					index.CopyTo(parameters, 0);

 				this.setMethod.Invoke(obj, invokeAttr, binder, parameters, culture);
 			} 
			else
 			{ 
				this.originalPropertyInfo.SetValue(obj, value, invokeAttr, binder, index, culture); 
			}
		} 

 		public override MethodInfo[] GetAccessors(bool nonPublic)
		{
 			return new MethodInfo[] { this.getMethod, this.setMethod }; 
 		}
 
		public override PropertyAttributes Attributes 
 		{
			get { return PropertyAttributes.None; } 
		}
		public override bool CanRead
 		{
			get 
 			{
 				if (this.getMethod != null) 
					return true; 
 				else if (this.originalPropertyInfo != null)
					return this.originalPropertyInfo.CanRead; 
				else
					return false;
 			}
		} 
 		public override bool CanWrite
 		{ 
			get 
 			{
				if (this.setMethod != null) 
					return true;
				else if (this.originalPropertyInfo != null)
 					return this.originalPropertyInfo.CanWrite;
				else 
 					return false;
 			} 
		} 
 		public override Type DeclaringType
		{ 
			get { return this.declaringType; }
		}
 		public override Type ReflectedType
		{ 
 			get { return this.declaringType; }
 		} 
		public override object[] GetCustomAttributes(bool inherit) 
 		{
			return new object[0]; 
		}
		public override object[] GetCustomAttributes(Type attributeType, bool inherit)
 		{
			return new object[0]; 
 		}
 		public override bool IsDefined(Type attributeType, bool inherit) 
		{ 
 			throw new NotSupportedException();
		} 
	}
	#endregion

 	#region PathParser 

	internal enum SourceValueType 
 	{ 
 		Property,
		Indexer 
 	};

	internal enum DrillIn
	{ 
		Never,
 		IfNeeded 
	}; 

 	internal struct SourceValueInfo 
 	{
		internal SourceValueType type;
 		internal DrillIn drillIn;
		internal string name; 

		internal SourceValueInfo(SourceValueType t, DrillIn d, string n) 
		{ 
 			type = t;
			drillIn = d; 
 			name = n;
 		}
	}
 
 	internal sealed class PathParser
	{ 
		private string error = string.Empty; 
		private State state;
 		private string pathValue; 
		private int index;
 		private int pathLength;
 		private DrillIn drillIn;
		private List al = new List(); 
 		private const char NullChar = Char.MinValue;
		private static List EmptyInfo = new List(1); 
		private static string SpecialChars = @".[]"; 

		private enum State 
 		{
			Init,
 			Prop,
 			Done 
		};
 
 		internal String Error 
		{
			get 
			{
 				return error;
			}
 		} 

 		internal List Parse(string path, bool returnResultBeforeError) 
		{ 
 			this.pathValue = (path != null) ? path.Trim() : String.Empty;
			this.pathLength = this.pathValue.Length; 
			this.index = 0;
			this.drillIn = DrillIn.IfNeeded;

 			this.al.Clear(); 
			this.error = null;
 			this.state = State.Init; 
 
 			if (this.pathLength > 0 && this.pathValue[0] == '.')
			{ 
 				//empty first prop - > input path was like ".bar"; need to add first empty property
				SourceValueInfo info = new SourceValueInfo(SourceValueType.Property, this.drillIn, string.Empty);
				this.al.Add(info);
			} 

 			while (this.state != State.Done) 
			{ 
 				char c = (this.index < this.pathLength) ? this.pathValue[this.index] : NullChar;
 				switch (this.state) 
				{
 					case State.Init:
						switch (c)
						{ 
							case '/':
 							case '.': 
							case '[': 
 							case NullChar:
 								this.state = State.Prop; 
								break;
 							case ']'://unexpected close indexer, report error
								this.error = "path[" + this.index + "] = " + c;
								return returnResultBeforeError ? this.al : EmptyInfo; 

							default: 
 								AddProperty(); 
								break;
 						} 
 						break;

					case State.Prop:
 						bool isIndexer = false; 
						switch (c)
						{ 
							case '.': 
 								this.drillIn = DrillIn.Never;
								break; 
 							case '[':
 								isIndexer = true;
								break;
 							case NullChar: 
								--this.index;
								break; 
							default: 
 								this.error = "path[" + this.index + "] = " + c;
								return returnResultBeforeError ? this.al : EmptyInfo; 
 						}
 						++this.index;      // skip over special character
						if (isIndexer)
 							AddIndexer(); 
						else
							AddProperty(); 
						break; 
 				}
			} 
 			
 			return (this.error == null || returnResultBeforeError) ? this.al : EmptyInfo;
		}
 
 		private void AddProperty()
		{ 
			int start = this.index; 
			while (this.index < this.pathLength && SpecialChars.IndexOf(this.pathValue[this.index]) < 0)
 				++this.index; 

			string name = this.pathValue.Substring(start, this.index - start).Trim();
 			SourceValueInfo info = new SourceValueInfo(
 										SourceValueType.Property, 
										this.drillIn, name);
 			this.al.Add(info); 
			StartNewLevel(); 
		}
 
		private void AddIndexer()
 		{
			int start = this.index;
 			int level = 1; 
 			while (level > 0)
			{ 
 				if (this.index >= this.pathLength) 
				{
					return; 
				}
 				if (this.pathValue[this.index] == '[')
					++level;
 				else if (this.pathValue[this.index] == ']') 
 					--level;
				++this.index; 
 			} 
			string name = this.pathValue.Substring(start, this.index - start - 1).Trim();
			SourceValueInfo info = new SourceValueInfo( 
										SourceValueType.Indexer,
 										this.drillIn, name);
			this.al.Add(info);
 			StartNewLevel(); 
 		}
 
		private void StartNewLevel() 
 		{
			if (this.index >= this.pathLength) 
				this.state = State.Done;
			this.drillIn = DrillIn.Never;
 		}
	} 

 	#endregion 
} 


// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
´╗┐namespace System.Workflow.ComponentModel 
{
    #region Using directives

    using System; 
    using System.IO;
    using System.Xml; 
    using System.Text; 
    using System.CodeDom;
    using System.Reflection; 
    using System.Xml.XPath;
    using System.Collections;
    using System.Xml.Serialization;
    using System.Collections.Generic; 
    using System.ComponentModel;
    using System.Collections.Specialized; 
    using System.ComponentModel.Design; 
    using System.ComponentModel.Design.Serialization;
    using System.Diagnostics; 
    using System.Globalization;
    using System.Drawing.Design;
    using System.Workflow.ComponentModel.Compiler;
    using System.Workflow.ComponentModel.Serialization; 
    using System.Workflow.ComponentModel.Design;
    using System.Configuration; 
    #endregion 

    #region Bind 
 	[Browsable(false)]
	internal abstract class BindBase
    {
		[NonSerialized] 
        protected bool designMode = true;
        [NonSerialized] 
        private object syncRoot = new object(); 

        public abstract object GetRuntimeValue(Activity activity); 
        public abstract object GetRuntimeValue(Activity activity, Type targetType);
		public abstract void SetRuntimeValue(Activity activity, object value);

 		protected virtual void OnRuntimeInitialized(Activity activity) 
		{
 		} 
 	} 

	#endregion 

 	#region Redundant Binds

	#region MemberBind 
	//
 
 	internal abstract class MemberBind : BindBase 
	{
 		private string name = string.Empty; 

 		protected MemberBind()
		{
 		} 

		protected MemberBind(string name) 
		{ 
			this.name = name;
 		} 

		[DefaultValue("")]
 		public string Name
 		{ 
			get
 			{ 
				return this.name; 
			}
		} 

 		internal static object GetValue(MemberInfo memberInfo, object dataContext, string path)
		{
 			if (memberInfo == null) 
 				throw new ArgumentNullException("memberInfo");
			if (dataContext == null) 
 				throw new ArgumentNullException("dataContext"); 
			if (path == null)
				path = string.Empty; 

			if (string.IsNullOrEmpty(path))
 				return null;
 
			object targetObject = dataContext;
 			System.Type memberType = dataContext.GetType(); 
 
 			PathWalker pathWalker = new PathWalker();
			pathWalker.MemberFound += delegate(object sender, PathMemberInfoEventArgs eventArgs) 
 			{
                if (targetObject == null)
                {
                    eventArgs.Action = PathWalkAction.Cancel; 
                    return;
                } 
                switch (eventArgs.MemberKind) 
				{
					case PathMemberKind.Field: 
						memberType = (eventArgs.MemberInfo as FieldInfo).FieldType;
 						targetObject = (eventArgs.MemberInfo as FieldInfo).GetValue(targetObject);
						break;
 
 					case PathMemberKind.Event:
 						EventInfo evt = eventArgs.MemberInfo as EventInfo; 
						memberType = evt.EventHandlerType; 

 						// GetValue() returns the actual value of the property.  We need the Bind object here. 
						// Find out if there is a matching dependency property and get the value throw the DP.
                        DependencyObject dependencyObject = targetObject as DependencyObject;
                        DependencyProperty dependencyProperty = DependencyProperty.FromName(evt.Name, dependencyObject.GetType());
						if (dependencyProperty != null && dependencyObject != null) 
						{
 							if(dependencyObject.IsBindingSet(dependencyProperty)) 
								targetObject = dependencyObject.GetBinding(dependencyProperty); 
 							else
 								targetObject = dependencyObject.GetHandler(dependencyProperty); 
						}
 						else
							targetObject = null;
 
						//
						eventArgs.Action = PathWalkAction.Stop; 
 						break; 

					case PathMemberKind.Property: 
 						memberType = (eventArgs.MemberInfo as PropertyInfo).PropertyType;
 						if (!(eventArgs.MemberInfo as PropertyInfo).CanRead)
						{
 							eventArgs.Action = PathWalkAction.Cancel; 
							return;
						} 
 
						targetObject = (eventArgs.MemberInfo as PropertyInfo).GetValue(targetObject, null);
 						break; 

					case PathMemberKind.IndexedProperty:
 						memberType = (eventArgs.MemberInfo as PropertyInfo).PropertyType;
 						if (!(eventArgs.MemberInfo as PropertyInfo).CanRead) 
						{
 							eventArgs.Action = PathWalkAction.Cancel; 
							return; 
						}
 
						targetObject = (eventArgs.MemberInfo as PropertyInfo).GetValue(targetObject, eventArgs.IndexParameters);
 						break;

					case PathMemberKind.Index:// 
 						memberType = (eventArgs.MemberInfo as PropertyInfo).PropertyType;
 						targetObject = (eventArgs.MemberInfo as PropertyInfo).GetValue(targetObject, BindingFlags.GetProperty, null, eventArgs.IndexParameters, CultureInfo.InvariantCulture); 
						break; 
 				}
                if (targetObject == null) 
                {
                    if (eventArgs.LastMemberInThePath)
                    {
                        eventArgs.Action = PathWalkAction.Cancel; 
                        return;
                    } 
                    else 
                    {
                        throw new InvalidOperationException(SR.GetString(SR.Error_BindPathNullValue, eventArgs.Path)); 
                    }
                }
			};
 
			if (pathWalker.TryWalkPropertyPath(memberType, path))
			{ 
 				//success 
				return ((targetObject != dataContext) ? targetObject : null);
 			} 
 			else
			{
 				//failure
				return null; 
			}
		} 
 
 		internal static void SetValue(object dataContext, string path, object value)
		{ 
 			if (dataContext == null)
 				throw new ArgumentNullException("dataContext");
			if (string.IsNullOrEmpty(path))
 				throw new ArgumentNullException("path"); 

			object parentObj = null; 
			object obj = dataContext; 

			object[] args = null; 
 			MemberInfo memberInfo = null;

			PathWalker pathWalker = new PathWalker();
 			pathWalker.MemberFound += delegate(object sender, PathMemberInfoEventArgs eventArgs) 
 			{
				// 
 				if (obj == null) 
				{
					eventArgs.Action = PathWalkAction.Cancel; 
					return;
 				}

				parentObj = obj; 
 				memberInfo = eventArgs.MemberInfo;
 
 				switch (eventArgs.MemberKind) 
				{
 					case PathMemberKind.Field: 
						obj = (eventArgs.MemberInfo as FieldInfo).GetValue(parentObj);
						args = null;
						break;
 
 					case PathMemberKind.Event:
						// 
 						eventArgs.Action = PathWalkAction.Cancel;//set value is not supported on events 
 						return;
 
					case PathMemberKind.Property:
 						obj = (eventArgs.MemberInfo as PropertyInfo).GetValue(parentObj, null);
						args = null;
						break; 

					case PathMemberKind.IndexedProperty: 
 					case PathMemberKind.Index: 
						obj = (eventArgs.MemberInfo as PropertyInfo).GetValue(parentObj, eventArgs.IndexParameters);
 						args = eventArgs.IndexParameters; 
 						break;
				}
 			};
 
			if (pathWalker.TryWalkPropertyPath(dataContext.GetType(), path))
			{ 
				//at this point the 'obj' holds the old value, we will be changing it to 'value' 
 				//success
				if (memberInfo is FieldInfo) 
 				{
 					(memberInfo as FieldInfo).SetValue(parentObj, value);
				}
 				else if (memberInfo is PropertyInfo) 
				{
                    if ((memberInfo as PropertyInfo).CanWrite) 
                        (memberInfo as PropertyInfo).SetValue(parentObj, value, args); 
                    else
                        throw new InvalidOperationException(SR.GetString(SR.Error_ReadOnlyField, memberInfo.Name)); 
				}
			}
 		}
 
		internal static ValidationError ValidateTypesInPath(Type srcType, string path)
 		{ 
 			ValidationError error = null; 

			if (srcType == null) 
 				throw new ArgumentNullException("srcType");
			if (path == null)
				throw new ArgumentNullException("path");
			if (path.Length == 0) 
 				throw new ArgumentException(SR.GetString(SR.Error_EmptyPathValue), "path");
 
            Debug.Assert(WorkflowCompilationContext.Current != null, "Can't have checkTypes set to true without a context in scope"); 
            IList authorizedTypes = WorkflowCompilationContext.Current.GetAuthorizedTypes();
			if (authorizedTypes == null) 
 			{
 				return new ValidationError(SR.GetString(SR.Error_ConfigFileMissingOrInvalid), ErrorNumbers.Error_ConfigFileMissingOrInvalid);
			}
 
 			Type propertyType = srcType;
			MemberInfo memberInfo = null; 
 
			PathWalker pathWalker = new PathWalker();
			pathWalker.MemberFound += delegate(object sender, PathMemberInfoEventArgs eventArgs) 
 			{
				Type memberType = null;
 				memberInfo = eventArgs.MemberInfo;
 
 				if (memberInfo is FieldInfo)
					memberType = ((FieldInfo)memberInfo).FieldType; 
 
 				if (memberInfo is PropertyInfo)
					memberType = ((PropertyInfo)memberInfo).PropertyType; 

				if (memberType != null && !SafeType(authorizedTypes, memberType))
				{
 					error = new ValidationError(SR.GetString(SR.Error_TypeNotAuthorized, memberType), ErrorNumbers.Error_TypeNotAuthorized); 
					eventArgs.Action = PathWalkAction.Stop;
 					return; 
 				} 
			};
 			pathWalker.TryWalkPropertyPath(propertyType, path); 
			return error;
		}

		private static bool SafeType(IList authorizedTypes, Type referenceType) 
 		{
			bool authorized = false; 
 			foreach (AuthorizedType authorizedType in authorizedTypes) 
 			{
				if (authorizedType.RegularExpression.IsMatch(referenceType.AssemblyQualifiedName)) 
 				{
					authorized = (String.Compare(bool.TrueString, authorizedType.Authorized, StringComparison.OrdinalIgnoreCase) == 0);
					if (!authorized)
					    return false; 
 				}
			} 
            return authorized; 
 		}
 

 		internal static MemberInfo GetMemberInfo(Type srcType, string path)
		{
 			if (srcType == null) 
				throw new ArgumentNullException("srcType");
			if (path == null) 
				throw new ArgumentNullException("path"); 
 			if (path.Length == 0)
				throw new ArgumentException(SR.GetString(SR.Error_EmptyPathValue), "path"); 

 			Type propertyType = srcType;
 			MemberInfo memberInfo = null;
 
			PathWalker pathWalker = new PathWalker();
 			pathWalker.MemberFound += delegate(object sender, PathMemberInfoEventArgs eventArgs) 
			{ 
				memberInfo = eventArgs.MemberInfo;
				if (eventArgs.MemberKind == PathMemberKind.Event) 
 				{
					//need to exit!!!
 					eventArgs.Action = PathWalkAction.Stop;
 					return; 
				}
 			}; 
 
			if (pathWalker.TryWalkPropertyPath(propertyType, path))
				return memberInfo; 
			else
 				return null;
		}
 	} 
 	#endregion
 
	#region FieldBind 
 	[ActivityValidator(typeof(FieldBindValidator))]
	internal sealed class FieldBind : MemberBind 
	{
		private string path = string.Empty;

 		public FieldBind() 
		{
 		} 
 
 		public FieldBind(string name)
			: base(name) 
 		{
		}

		public FieldBind(string name, string path) 
			: base(name)
 		{ 
			this.path = path; 
 		}
 
 		public string Path
		{
 			get
			{ 
				return this.path;
			} 
 			set 
			{
 				if (!this.designMode) 
 					throw new InvalidOperationException(SR.GetString(SR.Error_CanNotChangeAtRuntime));

				this.path = value;
 			} 
		}
 
		public override object GetRuntimeValue(Activity activity, Type targetType) 
		{
 			throw new NotImplementedException(); 
		}

 		public override object GetRuntimeValue(Activity activity)
 		{ 
			throw new NotImplementedException();
 		} 
 
		public override void SetRuntimeValue(Activity activity, object value)
		{ 
			throw new NotImplementedException();
 		}

 
		protected override void OnRuntimeInitialized(Activity activity)
 		{ 
 			throw new NotImplementedException(); 
		}
 	} 

	#endregion

	#region PropertyBind 
	[ActivityValidator(typeof(PropertyBindValidator))]
 	internal sealed class PropertyBind : MemberBind 
	{ 
 		private string path = string.Empty;
 
 		public PropertyBind()
		{
 		}
 
		public PropertyBind(string name)
			: base(name) 
		{ 
 		}
 
		public PropertyBind(string name, string path)
 			: base(name)
 		{
			this.path = path; 
 		}
 
		public string Path 
		{
			get 
 			{
				return this.path;
 			}
 			set 
			{
 				if (!this.designMode) 
					throw new InvalidOperationException(SR.GetString(SR.Error_CanNotChangeAtRuntime)); 

				this.path = value; 
			}
 		}

		public override object GetRuntimeValue(Activity activity, Type targetType) 
 		{
 			throw new NotImplementedException(); 
		} 

 		public override object GetRuntimeValue(Activity activity) 
		{
			throw new NotImplementedException();
		}
 
 		public override void SetRuntimeValue(Activity activity, object value)
		{ 
 			throw new NotImplementedException(); 
 		}
	} 

 	#endregion

	#region MethodBind 
	[ActivityValidator(typeof(MethodBindValidator))]
	internal sealed class MethodBind : MemberBind 
 	{ 
		public MethodBind()
 		{ 
 		}

		public MethodBind(string name)
 			: base(name) 
		{
		} 
 
		public override object GetRuntimeValue(Activity activity, Type targetType)
 		{ 
            throw new NotImplementedException();
		}

 		public override object GetRuntimeValue(Activity activity) 
 		{
			throw new Exception(SR.GetString(SR.Error_NoTargetTypeForMethod)); 
 		} 

		public override void SetRuntimeValue(Activity activity, object value) 
		{
			throw new Exception(SR.GetString(SR.Error_MethodDataSourceIsReadOnly));
 		}
	} 
 	#endregion
 
 	#endregion 

	#region ActivityBind 
    internal enum ActivityBindTypes { Field = 1, Property = 2, Method = 3 };

    [Browsable(true)]
    [TypeConverter(typeof(ActivityBindTypeConverter))] 
 	[ActivityValidator(typeof(ActivityBindValidator))]
    [DesignerSerializer(typeof(BindMarkupExtensionSerializer), typeof(WorkflowMarkupSerializer))] 
	public sealed class ActivityBind : MarkupExtension, IPropertyValueProvider 
	{
		#region stuff from the former Bind 
 		[NonSerialized]
		private bool designMode = true;
        [NonSerialized]
        private bool dynamicUpdateMode = false; 
        [NonSerialized]
 		private IDictionary userData = null; 
 		[NonSerialized] 
		private object syncRoot = new object();
 
 		internal void SetContext(Activity activity)
		{
			this.designMode = false;
			OnRuntimeInitialized(activity); 
 		}
 
        internal bool DynamicUpdateMode 
        {
            get 
            {
                return this.dynamicUpdateMode;
            }
            set 
            {
                this.dynamicUpdateMode = false; 
            } 
        }
 

		[Browsable(false)]
 		[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
 		private bool DesignMode 
		{
 			get 
			{ 
                return this.designMode && !this.dynamicUpdateMode;
			} 
		}

 		[Browsable(false)]
		[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] 
 		public IDictionary UserData
 		{ 
			get 
 			{
				if (this.userData == null) 
				{
					lock (this.syncRoot)
 					{
						if (this.userData == null) 
 							this.userData = Hashtable.Synchronized(new Hashtable());
 					} 
				} 
 				return this.userData;
			} 
		}

		internal static object GetDataSourceObject(Activity activity, string inputName, out string name)
 		{ 
			if (activity == null)
 				throw new ArgumentNullException("activity"); 
 			if (string.IsNullOrEmpty(inputName)) 
				throw new ArgumentNullException("inputName");
 
 			Activity contextActivity = Helpers.GetDataSourceActivity(activity, inputName, out name);
			return contextActivity;
		}
		#endregion 

 		private string id = string.Empty; 
		private string path = string.Empty; 

 		public ActivityBind() 
 		{
		}

        public ActivityBind(string name) 
        {
            this.id = name; 
        } 

 		public ActivityBind(string name, string path) 
		{
			this.id = name;
			this.path = path;
 		} 

		[DefaultValue("")] 
        [SRDescription(SR.ActivityBindIDDescription)] 
        [ConstructorArgument("name")]
        public string Name 
 		{
 			get
			{
 				return this.id; 
			}
			set 
			{ 
 				if (!this.DesignMode)
					throw new InvalidOperationException(SR.GetString(SR.Error_CanNotChangeAtRuntime)); 

 				this.id = value;
 			}
		} 

 		[DefaultValue("")] 
		[SRDescription(SR.ActivityBindPathDescription)] 
        [TypeConverter(typeof(ActivityBindPathTypeConverter))]
		public string Path 
		{
 			get
			{
 				return this.path; 
 			}
			set 
 			{ 
				if (!this.DesignMode)
					throw new InvalidOperationException(SR.GetString(SR.Error_CanNotChangeAtRuntime)); 

				this.path = value;
 			}
		} 

        public override object ProvideValue(IServiceProvider provider) 
        { 
            return this;
        } 

 		public object GetRuntimeValue(Activity activity, Type targetType)
 		{
			if (activity == null) 
 				throw new ArgumentNullException("activity");
			if (targetType == null) 
				throw new ArgumentNullException("targetType"); 
			return this.InternalGetRuntimeValue(activity, targetType);
 		} 

		public object GetRuntimeValue(Activity activity)
 		{
 			if (activity == null) 
				throw new ArgumentNullException("activity");
 			return this.InternalGetRuntimeValue(activity, null); 
		} 

		private object InternalGetRuntimeValue(Activity activity, Type targetType) 
		{
 			object runtimeValue = null;
            Activity referencedActivity = Helpers.ParseActivityForBind(activity, this.Name);
			if (referencedActivity != null) 
 			{
 				//Now lets get the MemberInfo 
				MemberInfo memberInfo = ActivityBind.GetMemberInfo(referencedActivity.GetType(), Path, targetType); 
 				if (memberInfo != null)
				{ 
					runtimeValue = ActivityBind.GetMemberValue(referencedActivity, memberInfo, Path, targetType);
					if (runtimeValue is ActivityBind && BindHelpers.GetMemberType(memberInfo) != typeof(ActivityBind))
 						runtimeValue = ((ActivityBind)runtimeValue).GetRuntimeValue(referencedActivity, targetType);
				} 
                else
                { 
                    // The value of this ActivityBind is bound to properties or events defined on the referenced activity 
                    // Note that we don't have corresponding logic for SetRuntimeValue because value should be only set
                    // at the end of the activity reference chain. 
                    Activity rootActivity = Helpers.GetRootActivity(activity);
                    DependencyProperty dependencyProperty = DependencyProperty.FromName(this.Path, rootActivity.GetType());
                }
 			} 
 			return runtimeValue;
		} 
 
 		public void SetRuntimeValue(Activity activity, object value)
		{ 
			if (activity == null)
				throw new ArgumentNullException("activity");

            Activity referencedActivity = Helpers.ParseActivityForBind(activity, this.Name); 
 			if (referencedActivity != null)
			{ 
 				MemberInfo memberInfo = ActivityBind.GetMemberInfo(referencedActivity.GetType(), Path, null); 
 				if (memberInfo != null)
				{ 
 					ActivityBind bind = ActivityBind.GetMemberValue(referencedActivity, memberInfo, Path, null) as ActivityBind;
					if (bind != null)
						bind.SetRuntimeValue(referencedActivity, value);
					else 
 						MemberBind.SetValue(referencedActivity, this.Path, value);
				} 
 				// Dependency property 
 				/*else
				{ 
 					Activity rootActivity = Helpers.GetRootActivity(activity);
					DependencyProperty dependencyProperty = DependencyProperty.FromName(this.Path, rootActivity.GetType());
					if (dependencyProperty != null)
					{ 
 						referencedActivity.SetValue(dependencyProperty, value);
					} 
 				}*/ 
 			}
		} 

 		private void OnRuntimeInitialized(Activity activity)
		{
			Activity dataSourceActivity = null; 
			ActivityBind activityBind = ActivityBind.GetContextBind(this, activity, out dataSourceActivity);
 			if (activityBind != null && dataSourceActivity != null) 
			{ 
 				Type companionType = dataSourceActivity.GetType();
 				if (companionType != null) 
				{
 					MemberInfo memberInfo = ActivityBind.GetMemberInfo(companionType, activityBind.Path, null);
					if (memberInfo != null)
					{ 
						if (memberInfo is FieldInfo || memberInfo is PropertyInfo || memberInfo is EventInfo)
 						{ 
							if (activityBind.UserData[UserDataKeys.BindDataSource] == null) 
 								activityBind.UserData[UserDataKeys.BindDataSource] = new Hashtable();
 
 							((Hashtable)activityBind.UserData[UserDataKeys.BindDataSource])[activity.QualifiedName] = memberInfo;
							if (dataSourceActivity != null)
 							{
								if (activityBind.UserData[UserDataKeys.BindDataContextActivity] == null) 
									activityBind.UserData[UserDataKeys.BindDataContextActivity] = new Hashtable();
								((Hashtable)activityBind.UserData[UserDataKeys.BindDataContextActivity])[activity.QualifiedName] = dataSourceActivity.QualifiedName; 
 							} 
						}
 					} 
 					/*else
					{
 						Activity rootActivity = Helpers.GetRootActivity(activity);
						DependencyProperty dependencyProperty = DependencyProperty.FromName(activityBind.Path, rootActivity.GetType()); 
						if (dependencyProperty != null)
						{ 
 							if (activityBind.UserData[UserDataKeys.BindDataSource] == null) 
								activityBind.UserData[UserDataKeys.BindDataSource] = new Hashtable();
 
 							((Hashtable)activityBind.UserData[UserDataKeys.BindDataSource])[activity.QualifiedName] = dependencyProperty;

 							if (dataSourceActivity != null)
							{ 
 								if (activityBind.UserData[UserDataKeys.BindDataContextActivity] == null)
									activityBind.UserData[UserDataKeys.BindDataContextActivity] = new Hashtable(); 
								((Hashtable)activityBind.UserData[UserDataKeys.BindDataContextActivity])[activity.QualifiedName] = dataSourceActivity.QualifiedName; 
							}
 						} 
					}*/
 				}
 			}
		} 

 		public override string ToString() 
		{ 
            Activity activity = UserData[UserDataKeys.BindDataContextActivity] as Activity;
            if (activity != null) 
            {
                string bindString = String.Empty;
                if (!string.IsNullOrEmpty(Name))
                    bindString = Helpers.ParseActivityForBind(activity, Name).QualifiedName; 

                if (!string.IsNullOrEmpty(Path)) 
                { 
                    string path = Path;
                    int indexOfSeparator = path.IndexOfAny(new char[] { '.', '/', '[' }); 
                    path = ((indexOfSeparator != -1)) ? path.Substring(0, indexOfSeparator) : path;
                    bindString += (!String.IsNullOrEmpty(bindString)) ? "." + path : path;
                }
 
                return bindString;
            } 
            else 
            {
                return base.ToString(); 
            }
        }

        #region Runtime / Validation Time Helpers 
        internal static MemberInfo GetMemberInfo(Type dataSourceType, string path, Type targetType)
		{ 
			MemberInfo memberInfo = MemberBind.GetMemberInfo(dataSourceType, path); 

 			//The events can be either bound to properties or can be bound to methods, 
			//There are cases where fields and methods can be of same name so in that case we either make sure for
 			//in the case of event handlers we either find Property or a Method
            if (targetType != null && typeof(Delegate).IsAssignableFrom(targetType) && (memberInfo == null || !(memberInfo is EventInfo)))
            { 
 				MethodInfo delegateMethod = targetType.GetMethod("Invoke");
				List paramTypes = new List(); 
 				foreach (ParameterInfo paramInfo in delegateMethod.GetParameters()) 
					paramTypes.Add(paramInfo.ParameterType);
 
				memberInfo = dataSourceType.GetMethod(path, BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.FlattenHierarchy, null, paramTypes.ToArray(), null);
			}

 			return memberInfo; 
		}
 
 		private static object GetMemberValue(object dataSourceObject, MemberInfo memberInfo, string path, Type targetType) 
 		{
			object memberValue = null; 
 			if (memberInfo is FieldInfo || memberInfo is PropertyInfo || memberInfo is EventInfo)
			{
				memberValue = MemberBind.GetValue(memberInfo, dataSourceObject, path);
				 
 				/*if (memberValue != null && targetType != null &&
					(memberValue.GetType().IsPrimitive || memberValue.GetType().IsEnum || memberValue.GetType() == typeof(string)) 
 					&& !targetType.IsAssignableFrom(memberValue.GetType())) 
 				{
					try 
 					{
						memberValue = Convert.ChangeType(memberValue, targetType, CultureInfo.InvariantCulture);
					}
					catch (Exception e) 
 					{
						throw new Exception(SR.GetString(SR.Error_DataSourceTypeConversionFailed, memberInfo.Name, memberValue.ToString(), targetType.FullName), e); 
 					} 
 				}*/
			} 
 			else if (targetType != null && memberInfo is MethodInfo)
			{
				memberValue = Delegate.CreateDelegate(targetType, dataSourceObject, (MethodInfo)memberInfo);//the wrapper method will never be static (even if the original one is)
			} 
 			else
			{ 
 				throw new InvalidOperationException(SR.GetString(SR.Error_MemberNotFound)); 
 			}
 
			return memberValue;
 		}

		//This function is used to get the outermost activity bind which is bound to actual field/property 
        //The function is called in OnRuntimeInitialized and makes sure that we get outer target bind and cache
        //it so that at runtime we do not have to walk the bind chain to find the bound member 
		private static ActivityBind GetContextBind(ActivityBind activityBind, Activity activity, out Activity contextActivity) 
		{
 			if (activityBind == null) 
				throw new ArgumentNullException("activityBind");
 			if (activity == null)
 				throw new ArgumentNullException("activity");
 
			BindRecursionContext recursionContext = new BindRecursionContext();
 			ActivityBind contextBind = activityBind; 
			contextActivity = activity; 
			
			while (contextBind != null) 
 			{
                Activity resolvedActivity = Helpers.ParseActivityForBind(contextActivity, contextBind.Name);
				if (resolvedActivity == null)
 					return null; 

 				object dataSourceObject = resolvedActivity; 
				MemberInfo memberInfo = ActivityBind.GetMemberInfo(dataSourceObject.GetType(), contextBind.Path, null); 
 				if (memberInfo == null)
				{ 
					contextActivity = resolvedActivity;
					return contextBind;
 				}
				else if (memberInfo is FieldInfo) 
 				{
 					contextActivity = resolvedActivity; 
					return contextBind; 
 				}
				else if(memberInfo is PropertyInfo && (memberInfo as PropertyInfo).PropertyType == typeof(ActivityBind) && dataSourceObject != null) 
				{
					object value = MemberBind.GetValue(memberInfo, dataSourceObject, contextBind.Path);
 					if (value is ActivityBind)
					{ 
 						if (recursionContext.Contains(contextActivity, contextBind))
 							return null; 
 
						recursionContext.Add(contextActivity, contextBind);
 						contextActivity = resolvedActivity; 
						contextBind = value as ActivityBind;
					}
					else
 					{ 
						return null;
 					} 
 				} 
				else
 				{ 
					return null;
				}
			}
 			return contextBind; 
        }
        #endregion 
 
        #region DesignTime Integration (DO NOT CALL THESE AT RUNTIME)
 
        #region Helper Functions
        // This function replaces Activity1.code1 with /ParentContext.code1.  This must be done for Binds that refer to
        // to fields, properties and methods in the top level custom activity data context.
        internal static string GetRelativePathExpression(Activity parentActivity, Activity childActivity) 
        {
            string relativeBindExpression = String.Empty; 
 
            Activity rootActivity = Helpers.GetRootActivity(childActivity);
            if (rootActivity == childActivity) 
                relativeBindExpression = "/Self";
            else
                relativeBindExpression = parentActivity.QualifiedName;
 
            return relativeBindExpression;
        } 
 
        #region IPropertyValueProvider Implementation
        ICollection IPropertyValueProvider.GetPropertyValues(ITypeDescriptorContext context) 
        {
            ArrayList values = new ArrayList();

            if (string.Equals(context.PropertyDescriptor.Name, "Path", StringComparison.Ordinal) && !String.IsNullOrEmpty(Name) && context.PropertyDescriptor is ActivityBindPathPropertyDescriptor) 
            {
                ITypeDescriptorContext outerPropertyContext = ((ActivityBindPathPropertyDescriptor)context.PropertyDescriptor).OuterPropertyContext; 
                if (outerPropertyContext != null) 
                {
                    Activity activity = PropertyDescriptorUtils.GetComponent(outerPropertyContext) as Activity; 
                    if (activity != null)
                    {
                        Activity targetActivity = Helpers.ParseActivityForBind(activity, Name);
                        if (targetActivity != null) 
                        {
                            foreach (MemberInfo memberInfo in ActivityBindPropertyDescriptor.GetBindableMembers(targetActivity, outerPropertyContext)) 
                                values.Add(memberInfo.Name); 
                        }
                    } 
                }
            }

            return values; 
        }
        #endregion 
 
        #endregion
 
        #endregion
    }
    #endregion
 
	#region BindRecursionContext
 
 	internal sealed class BindRecursionContext 
 	{
		private Hashtable activityBinds = new Hashtable(); 

 		public bool Contains(Activity activity, ActivityBind bind)
		{
			if (activity == null) 
				throw new ArgumentNullException("activity");
 			if (bind == null) 
				throw new ArgumentNullException("bind"); 

 			if (this.activityBinds[activity] != null) 
 			{
				List binds = this.activityBinds[activity] as List;
 				foreach (ActivityBind prevBind in binds)
				{ 
					if (prevBind.Path == bind.Path)
						return true; 
 				} 
			}
 			return false; 
 		}

		public void Add(Activity activity, ActivityBind bind)
 		{ 
			if (activity == null)
				throw new ArgumentNullException("activity"); 
			if (bind == null) 
 				throw new ArgumentNullException("bind");
			if (this.activityBinds[activity] == null) 
 				this.activityBinds[activity] = new List();

 			((List)this.activityBinds[activity]).Add(bind);
		} 
 	}
 
	#endregion 

	#region BindHelpers 
	internal static class BindHelpers
 	{
		internal static Type GetBaseType(IServiceProvider serviceProvider, PropertyValidationContext validationContext)
 		{ 
 			Type type = null;
			if (validationContext.Property is PropertyInfo) 
 			{ 
				type = Helpers.GetBaseType(validationContext.Property as PropertyInfo, validationContext.PropertyOwner, serviceProvider);
			} 
			else if (validationContext.Property is DependencyProperty)
 			{
				//
 				DependencyProperty dependencyProperty = validationContext.Property as DependencyProperty; 
 				if (dependencyProperty != null)
				{ 
 					if (type == null) 
					{
						IDynamicPropertyTypeProvider basetypeProvider = validationContext.PropertyOwner as IDynamicPropertyTypeProvider; 
						if (basetypeProvider != null)
                            type = basetypeProvider.GetPropertyType(serviceProvider, dependencyProperty.Name);
 					}
 
					if (type == null)
 						type = dependencyProperty.PropertyType; 
 				} 
			}
 
 			return type;
		}

		internal static AccessTypes GetAccessType(IServiceProvider serviceProvider, PropertyValidationContext validationContext) 
		{
 			AccessTypes accessType = AccessTypes.Read; 
			if (validationContext.Property is PropertyInfo) 
 			{
 				accessType = Helpers.GetAccessType(validationContext.Property as PropertyInfo, validationContext.PropertyOwner, serviceProvider); 
			}
 			else if (validationContext.Property is DependencyProperty)
			{
				IDynamicPropertyTypeProvider basetypeProvider = validationContext.PropertyOwner as IDynamicPropertyTypeProvider; 
				if (basetypeProvider != null)
                    accessType = basetypeProvider.GetAccessType(serviceProvider, ((DependencyProperty)validationContext.Property).Name); 
 			} 

			return accessType; 
 		}

 		internal static object ResolveActivityPath(Activity refActivity, string path)
		{ 
 			if (refActivity == null)
				throw new ArgumentNullException("refActivity"); 
			if (path == null) 
				throw new ArgumentNullException("path");
 			if (path.Length == 0) 
                throw new ArgumentException(SR.GetString(SR.Error_EmptyPathValue), "path");

			object value = refActivity;
 			BindRecursionContext recursionContext = new BindRecursionContext(); 

 			PathWalker pathWalker = new PathWalker(); 
			pathWalker.MemberFound += delegate(object sender, PathMemberInfoEventArgs eventArgs) 
 			{
				// If value is null, we don't want to use GetValue on the MemberInfo 
				if (value == null)
				{
 					eventArgs.Action = PathWalkAction.Cancel;//need to cancel the walk with the failure return result
					return; 
 				}
 
 				switch (eventArgs.MemberKind) 
				{
 					case PathMemberKind.Field: 
						try
						{
							value = (eventArgs.MemberInfo as FieldInfo).GetValue(value);
 						} 
						catch(Exception exception)
 						{ 
 							//in some cases the value might not be there yet (e.g. validation vs. runtime) 
							value = null;
 							eventArgs.Action = PathWalkAction.Cancel; 

							//we should throw only if we are at the runtime
							if (!refActivity.DesignMode)
							{ 
 								TargetInvocationException targetInvocationException = exception as TargetInvocationException;
								throw (targetInvocationException != null) ? targetInvocationException.InnerException : exception; 
 							} 
 						}
						break; 

 					case PathMemberKind.Event:
						EventInfo evt = eventArgs.MemberInfo as EventInfo;
 
						// GetValue() returns the actual value of the property.  We need the Bind object here.
						// Find out if there is a matching dependency property and get the value throw the DP. 
 						DependencyProperty eventDependencyProperty = DependencyProperty.FromName(evt.Name, value.GetType()); 
						if (eventDependencyProperty != null && value is DependencyObject)
 						{ 
 							if ((value as DependencyObject).IsBindingSet(eventDependencyProperty))
								value = (value as DependencyObject).GetBinding(eventDependencyProperty);
 							else
                                value = (value as DependencyObject).GetHandler(eventDependencyProperty); 
						}
						break; 
 
					case PathMemberKind.Property:
 						if (!(eventArgs.MemberInfo as PropertyInfo).CanRead) 
						{
 							eventArgs.Action = PathWalkAction.Cancel;
 							return;
						} 

 						// GetValue() returns the actual value of the property.  We need the Bind object here. 
						// Find out if there is a matching dependency property and get the value throw the DP. 
						DependencyProperty dependencyProperty = DependencyProperty.FromName(eventArgs.MemberInfo.Name, value.GetType());
                        if (dependencyProperty != null && value is DependencyObject && (value as DependencyObject).IsBindingSet(dependencyProperty)) 
                            value = (value as DependencyObject).GetBinding(dependencyProperty);
						else
 							try
							{ 
 								value = (eventArgs.MemberInfo as PropertyInfo).GetValue(value, null);
 							} 
							catch(Exception exception) 
 							{
								//property getter function might throw at design time, validation should not fail bacause of that 
								value = null;
								eventArgs.Action = PathWalkAction.Cancel;

 								//we should throw only if we are at the runtime 
								if (!refActivity.DesignMode)
 								{ 
 									TargetInvocationException targetInvocationException = exception as TargetInvocationException; 
									throw (targetInvocationException != null) ? targetInvocationException.InnerException : exception;
 								} 
							}
						break;

					case PathMemberKind.IndexedProperty: 
 					case PathMemberKind.Index:
						try 
 						{ 
 							value = (eventArgs.MemberInfo as PropertyInfo).GetValue(value, BindingFlags.GetProperty, null, eventArgs.IndexParameters, CultureInfo.InvariantCulture);
						} 
 						catch(Exception exception)
						{
							//in some cases the value might not be there yet - e.g. array or dictionary is populated at runtime only (validation vs. runtime)
							value = null; 
 							eventArgs.Action = PathWalkAction.Cancel;
							 
 							//we should throw only if we are at the runtime 
 							if (!refActivity.DesignMode)
							{ 
 								TargetInvocationException targetInvocationException = exception as TargetInvocationException;
								throw (targetInvocationException != null) ? targetInvocationException.InnerException : exception;
							}
						} 
 						break;
				} 
 
 				//need to unwrap the activity bind if we get one - to proceed with the actual field/property/delegate
 				//do not unwrap if the property/field is itself of type ActivityBind 
				//we should not unwrap the latest ActivityBind though - only intermediate ones
 				//avoid circular reference problems with the BindRecursionContext
				if (value is ActivityBind && !eventArgs.LastMemberInThePath && GetMemberType(eventArgs.MemberInfo) != typeof(ActivityBind))
				{ 
					while (value is ActivityBind)
 					{ 
						ActivityBind activityBind = value as ActivityBind; 
 						if (recursionContext.Contains(refActivity, activityBind))
 							throw new InvalidOperationException(SR.GetString(SR.Bind_ActivityDataSourceRecursionDetected)); 

						recursionContext.Add(refActivity, activityBind);
 						value = activityBind.GetRuntimeValue(refActivity);
					} 
				}
			}; 
 
 			if (pathWalker.TryWalkPropertyPath(refActivity.GetType(), path))
				return value; 
 			else
 				return null;
		}
 
 		internal static PropertyInfo GetMatchedPropertyInfo(Type memberType, string[] aryArgName, object[] args)
		{ 
			if (memberType == null) 
				throw new ArgumentNullException("memberType");
 			if (aryArgName == null) 
				throw new ArgumentNullException("aryArgName");
 			if (args == null)
 				throw new ArgumentNullException("args");
 
			MemberInfo[][] aryMembers = new MemberInfo[][] { memberType.GetDefaultMembers(), null };
 
            if (memberType.IsArray) 
            {
                MemberInfo[] getMember = memberType.GetMember("Get");//arrays will always implement that 
                MemberInfo[] setMember = memberType.GetMember("Set");//arrays will always implement that
                PropertyInfo getProperty = new ActivityBindPropertyInfo(memberType, getMember[0] as MethodInfo, setMember[0] as MethodInfo, string.Empty, null);
                aryMembers[1] = new MemberInfo[] { getProperty };
            } 

 			for (int index = 0; index < aryMembers.Length; ++index) 
			{ 
				if (aryMembers[index] == null)
					continue; 
 				MemberInfo[] defaultMembers = aryMembers[index];
				foreach (MemberInfo memberInfo in defaultMembers)
 				{
                    PropertyInfo propertyInfo = memberInfo as PropertyInfo; 
                    if (propertyInfo != null)
 					{ 
                        if (MatchIndexerParameters(propertyInfo, aryArgName, args)) 
                            return propertyInfo;
					} 
 				}
			}
			return null;
 
		}
 
        internal static bool MatchIndexerParameters(PropertyInfo propertyInfo, string[] argNames, object[] args) 
 		{
            if (propertyInfo == null) 
                throw new ArgumentNullException("propertyInfo");
			if (argNames == null)
 				throw new ArgumentNullException("argNames");
 			if (args == null) 
				throw new ArgumentNullException("args");
 
 			ParameterInfo[] aryPI = propertyInfo.GetIndexParameters(); 
			if (aryPI.Length != argNames.Length)
				return false; 

			for (int index = 0; index < args.Length; ++index)
 			{
				Type paramType = aryPI[index].ParameterType; 
 				if (paramType != typeof(String) && paramType != typeof(System.Int32))
 					return false; 
				try 
 				{
					object arg = null; 
					string argName = argNames[index].Trim();
					if (paramType == typeof(String) && argName.StartsWith("\"", StringComparison.Ordinal) && argName.EndsWith("\"", StringComparison.Ordinal))
 						arg = argName.Substring(1, argName.Length - 2).Trim();
					else if (paramType == typeof(System.Int32)) 
 						arg = Convert.ChangeType(argName, typeof(System.Int32), CultureInfo.InvariantCulture);
 
 					if (arg != null) 
						args.SetValue(arg, index);
 					else 
						return false;
				}
				catch
 				{ 
					return false;
 				} 
 			} 
			return true;
 		} 

		internal static Type GetMemberType(MemberInfo memberInfo)
		{
			FieldInfo fieldInfo = memberInfo as FieldInfo; 
 			if (fieldInfo != null)
				return fieldInfo.FieldType; 
 
 			PropertyInfo propertyInfo = memberInfo as PropertyInfo;
 			if (propertyInfo != null) 
			{
 				if (propertyInfo.PropertyType != null)
					return propertyInfo.PropertyType;
 
				//sometimes need to get the property type off the getter method
				MethodInfo getter = propertyInfo.GetGetMethod(); 
 				return getter.ReturnType; 
			}
 
 			EventInfo eventInfo = memberInfo as EventInfo;
 			if (eventInfo != null)
				return eventInfo.EventHandlerType;
 
 			return null;
		} 
    } 

	#endregion 

	#region Class PathWalker
 	internal enum PathMemberKind { Field, Event, Property, IndexedProperty, Index }
	internal enum PathWalkAction { Continue, Stop, Cancel };//stop returns true, while cancel returns false 

 	internal class PathMemberInfoEventArgs : EventArgs 
 	{ 
		private string path;
 		private Type parentType; 
		private PathMemberKind memberKind;
		private MemberInfo memberInfo;
		private object[] indexParameters = new object[0];//not empty for IndexedProperty and Index types
 		private PathWalkAction action = PathWalkAction.Continue; 
		private bool lastMemberInThePath = false;
 
 		public PathMemberInfoEventArgs(string path, Type parentType, MemberInfo memberInfo, PathMemberKind memberKind, bool lastMemberInThePath) 
 		{
			if (string.IsNullOrEmpty(path)) 
 				throw new ArgumentNullException("path");
			if (parentType == null)
				throw new ArgumentNullException("parentType");
			if (memberInfo == null) 
 				throw new ArgumentNullException("memberInfo");
 
			this.path = path; 
 			this.parentType = parentType;
 			this.memberInfo = memberInfo; 
			this.memberKind = memberKind;
 			this.lastMemberInThePath = lastMemberInThePath;
		}
 
		public PathMemberInfoEventArgs(string path, Type parentType, MemberInfo memberInfo, PathMemberKind memberKind, bool lastMemberInThePath, object[] indexParameters)
			: this(path, parentType, memberInfo, memberKind, lastMemberInThePath) 
 		{ 
			this.indexParameters = indexParameters;
 		} 

 		public string Path
		{
 			get { return this.path; } 
		}
		//public Type ParentType 
		//{ 
 		//    get { return this.parentType; }
		//} 
 		public MemberInfo MemberInfo
 		{
			get { return this.memberInfo; }
 		} 
		public PathMemberKind MemberKind
		{ 
			get { return this.memberKind; } 
 		}
		public object[] IndexParameters 
 		{
 			get { return this.indexParameters; }
		}
 		public bool LastMemberInThePath 
		{
			get { return this.lastMemberInThePath; } 
		} 
 		public PathWalkAction Action
		{ 
 			get { return this.action; }
 			set { this.action = value; }
		}
 	} 

	internal class PathErrorInfoEventArgs : EventArgs 
	{ 
		private SourceValueInfo info;
 		private string currentPath; 

		public PathErrorInfoEventArgs(SourceValueInfo info, string currentPath)
 		{
 			if (currentPath == null) 
				throw new ArgumentNullException("currentPath");
 
 			this.info = info; 
			this.currentPath = currentPath;
		} 

		//public SourceValueInfo Info
 		//{
		//    get { return this.info; } 
 		//}
 		//public string CurrentPath 
		//{ 
 		//    get { return this.currentPath; }
		//} 
	}

	//common path walker
 	//it is based off the property types and the PathParser results 
	//caller might keep a ref to the actual object and call Get/Set value on the members returned in the PathMemberInfoEventArgs
 	internal class PathWalker 
 	{ 
		public EventHandler MemberFound;//on every member along the path
 		public EventHandler PathErrorFound;//if there was an error parsing or walking the path 

		private static MemberInfo[] PopulateMembers(Type type, string memberName)
		{
			List members = new List(); 
 			members.AddRange(type.GetMember(memberName, MemberTypes.Field | MemberTypes.Property | MemberTypes.Event | MemberTypes.Method, BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance | BindingFlags.FlattenHierarchy));
 
			if (type.IsInterface) 
 			{
 				Type[] interfaces = type.GetInterfaces(); 
				foreach (Type implementedInterface in interfaces)
 				{
					members.AddRange(implementedInterface.GetMember(memberName, MemberTypes.Field | MemberTypes.Property | MemberTypes.Event | MemberTypes.Method, BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance | BindingFlags.FlattenHierarchy));
				} 
			}
 
 			return members.ToArray(); 
		}
 
 		public bool TryWalkPropertyPath(Type rootType, string path)
 		{
			if (rootType == null)
 				throw new ArgumentNullException("rootType"); 
			if (string.IsNullOrEmpty(path))
				throw new ArgumentNullException("path"); 
 
			Type propertyType = rootType;
 			string currentPath = string.Empty; 

			PathParser parser = new PathParser();
 			List pathInfo = parser.Parse(path, true);
 			string parsingError = parser.Error; 

			for (int i = 0; i < pathInfo.Count; i++) 
 			{ 
				SourceValueInfo info = pathInfo[i];
 
				if (string.IsNullOrEmpty(info.name))
				{
 					if (PathErrorFound != null)
						PathErrorFound(this, new PathErrorInfoEventArgs(info, currentPath)); 
 					
 					return false; 
				} 

 				string additionalPath = (info.type == SourceValueType.Property) ? info.name : "[" + info.name + "]"; 
				string newPath = (string.IsNullOrEmpty(currentPath)) ? additionalPath : currentPath + ((info.type == SourceValueType.Property) ? "." : string.Empty) + additionalPath;

				Type newPropertyType = null;
				MemberInfo newMemberInfo = null; 

 				switch (info.type) 
				{ 
 					case SourceValueType.Property:
 						MemberInfo[] members = PopulateMembers(propertyType, info.name); 
						if (members == null || members.Length == 0 || members[0] == null)
 						{
							if (PathErrorFound != null)
								PathErrorFound(this, new PathErrorInfoEventArgs(info, currentPath)); 
					
 							return false; 
						} 

 						newMemberInfo = members[0]; 
                        if (newMemberInfo is EventInfo || newMemberInfo is MethodInfo)
 						{
							if(MemberFound != null)
 							{ 
								PathMemberInfoEventArgs args = new PathMemberInfoEventArgs(newPath, propertyType, newMemberInfo, PathMemberKind.Event, i == pathInfo.Count - 1);
								MemberFound(this, args); 
 
								if (args.Action == PathWalkAction.Cancel)
 									return false; 
								else if (args.Action == PathWalkAction.Stop)
 									return true;
 							}
							 
 							//
							return string.IsNullOrEmpty(parsingError); 
						} 
						else if (newMemberInfo is PropertyInfo)
 						{ 
							//property getter could be an indexer
 							PropertyInfo memberPropertyInfo = newMemberInfo as PropertyInfo;
 							MethodInfo getterMethod = memberPropertyInfo.GetGetMethod();
							MethodInfo setterMethod = memberPropertyInfo.GetSetMethod(); 
 							ActivityBindPropertyInfo properyInfo = new ActivityBindPropertyInfo(propertyType, getterMethod, setterMethod, memberPropertyInfo.Name, memberPropertyInfo);
 
							newPropertyType = properyInfo.PropertyType; 
							ParameterInfo[] parameters = properyInfo.GetIndexParameters();
							if (parameters.Length > 0) 
 							{
								//need to check that the next parsed element is an indexer
 								if (i < pathInfo.Count - 1 && pathInfo[i + 1].type == SourceValueType.Indexer && !string.IsNullOrEmpty(pathInfo[i + 1].name))
 								{ 
									string[] arrayArgName = pathInfo[i + 1].name.Split(',');
 									object[] arguments = new object[arrayArgName.Length]; 
 
									//match the number/type of parameters from the following indexer item
									if (BindHelpers.MatchIndexerParameters(properyInfo, arrayArgName, arguments)) 
									{
 										newPath += "[" + pathInfo[i + 1].name + "]";
										
 										//indexer property, uses two of the parsed array elements 
 										if(MemberFound != null)
										{ 
 											PathMemberInfoEventArgs args = new PathMemberInfoEventArgs(newPath, propertyType, properyInfo, PathMemberKind.IndexedProperty, i == pathInfo.Count - 2, arguments); 
											MemberFound(this, args);
 
											if (args.Action == PathWalkAction.Cancel)
												return false;
 											else if (args.Action == PathWalkAction.Stop)
												return true; 
 										}
 
 										//skip the next indexer item too 
										i++;
 									} 
									else
									{
										//parameters didn't match
 										if (PathErrorFound != null) 
											PathErrorFound(this, new PathErrorInfoEventArgs(info, currentPath));
 										 
 										return false; 
									}
 								} 
								else
								{
									//trailing index is missing or empty for the indexed property
 									if (PathErrorFound != null) 
										PathErrorFound(this, new PathErrorInfoEventArgs(info, currentPath));
 										 
 									return false; 
								}
 							} 
							else // parameters.Length == 0
							{
								//a regular property
 								if(MemberFound != null) 
								{
 									PathMemberInfoEventArgs args = new PathMemberInfoEventArgs(newPath, propertyType, properyInfo, PathMemberKind.Property, i == pathInfo.Count - 1); 
 									MemberFound(this, args); 
									
 									if (args.Action == PathWalkAction.Cancel) 
										return false;
									else if (args.Action == PathWalkAction.Stop)
										return true;
 								} 
							}
 						} 
 						else 
						{
 							//that would be a field 
							if(MemberFound != null)
							{
								PathMemberInfoEventArgs args = new PathMemberInfoEventArgs(newPath, propertyType, newMemberInfo, PathMemberKind.Field, i == pathInfo.Count - 1);
 								MemberFound(this, args); 

								if (args.Action == PathWalkAction.Cancel) 
 									return false; 
 								else if (args.Action == PathWalkAction.Stop)
									return true; 
 							}

							newPropertyType = (newMemberInfo as FieldInfo).FieldType;
						} 

						break; 
 
 					case SourceValueType.Indexer:
						if (!string.IsNullOrEmpty(info.name)) 
 						{
 							string[] arrayArgName = info.name.Split(',');
							object[] arguments = new object[arrayArgName.Length];
 
 							PropertyInfo arrayPropertyInfo = BindHelpers.GetMatchedPropertyInfo(propertyType, arrayArgName, arguments);
							if(arrayPropertyInfo != null) 
							{ 
								if(MemberFound != null)
 								{ 
									PathMemberInfoEventArgs args = new PathMemberInfoEventArgs(newPath, propertyType, arrayPropertyInfo, PathMemberKind.Index, i == pathInfo.Count - 1, arguments);
 									MemberFound(this, args);

 									if (args.Action == PathWalkAction.Cancel) 
										return false;
 									else if (args.Action == PathWalkAction.Stop) 
										return true; 
								}
 
								newPropertyType = arrayPropertyInfo.PropertyType;
 								if(newPropertyType == null)
									newPropertyType = arrayPropertyInfo.GetGetMethod().ReturnType;
 							} 
 							else
							{ 
 								//did not mach number/type of arguments 
								if (PathErrorFound != null)
									PathErrorFound(this, new PathErrorInfoEventArgs(info, currentPath)); 
								
 								return false;
							}
 						} 
 						else
						{ 
 							//empty indexer 
							if (PathErrorFound != null)
								PathErrorFound(this, new PathErrorInfoEventArgs(info, currentPath)); 
										
 							return false;
						}
 
 						break;
 				} 
 
				propertyType = newPropertyType;
 				currentPath = newPath; 
			}

			return string.IsNullOrEmpty(parsingError);
		} 
 	}
 
	//multi-dimentional arrays dont implement default property 
 	//this fake property will help us to handle that
 	internal class ActivityBindPropertyInfo : PropertyInfo 
	{
 		private MethodInfo getMethod;
		private MethodInfo setMethod;
		private Type declaringType; 
		private string propertyName;
 		private PropertyInfo originalPropertyInfo;//in vb fields get returned as properties 
 
		public ActivityBindPropertyInfo(Type declaringType, MethodInfo getMethod, MethodInfo setMethod, string propertyName, PropertyInfo originalPropertyInfo)
 		{ 
 			if (declaringType == null)
				throw new ArgumentNullException("declaringType");
 			if (propertyName == null)
				throw new ArgumentNullException("propertyName"); 

			this.declaringType = declaringType; 
			this.getMethod = getMethod; 
 			this.setMethod = setMethod;
			this.propertyName = propertyName; 
 			this.originalPropertyInfo = originalPropertyInfo;//could be null for array indexers.
 		}

		public override string Name 
 		{
			get { return this.propertyName; } 
		} 

		public override MethodInfo GetGetMethod(bool nonPublic) 
 		{
			return this.getMethod;
 		}
 
 		public override MethodInfo GetSetMethod(bool nonPublic)
		{ 
 			return this.setMethod; 
		}
 
		public override Type PropertyType
		{
 			get
			{ 
 				if (this.getMethod != null)
 					return this.getMethod.ReturnType; 
				else if (this.originalPropertyInfo != null) 
 					return this.originalPropertyInfo.PropertyType;
				else 
					return typeof(object);
			}
 		}
 
		public override ParameterInfo[] GetIndexParameters()
 		{ 
 			if (this.getMethod != null) 
				return this.getMethod.GetParameters();
 			else if (this.originalPropertyInfo != null) 
				return this.originalPropertyInfo.GetIndexParameters();
			else
				return new ParameterInfo[0];
 		} 

		public override object GetValue(object obj, BindingFlags invokeAttr, Binder binder, object[] index, CultureInfo culture) 
 		{ 
 			if (this.getMethod == null && (this.originalPropertyInfo == null || !this.originalPropertyInfo.CanRead))
				throw new InvalidOperationException(SR.GetString(SR.Error_PropertyHasNoGetterDefined, this.propertyName)); 

 			if (this.getMethod != null)
				return this.getMethod.Invoke(obj, invokeAttr, binder, index, culture);
			else 
				return this.originalPropertyInfo.GetValue(obj, invokeAttr, binder, index, culture);
 		} 
 
		public override void SetValue(object obj, object value, BindingFlags invokeAttr, Binder binder, object[] index, CultureInfo culture)
 		{ 
 			if (this.setMethod == null && (this.originalPropertyInfo == null || !this.originalPropertyInfo.CanWrite))
				throw new InvalidOperationException(SR.GetString(SR.Error_PropertyHasNoSetterDefined, this.propertyName));

 			if (this.setMethod != null) 
			{
				object[] parameters = new object[((index != null) ? index.Length : 0) + 1]; 
				parameters[((index != null) ? index.Length : 0)] = value; 

 				if (index != null) 
					index.CopyTo(parameters, 0);

 				this.setMethod.Invoke(obj, invokeAttr, binder, parameters, culture);
 			} 
			else
 			{ 
				this.originalPropertyInfo.SetValue(obj, value, invokeAttr, binder, index, culture); 
			}
		} 

 		public override MethodInfo[] GetAccessors(bool nonPublic)
		{
 			return new MethodInfo[] { this.getMethod, this.setMethod }; 
 		}
 
		public override PropertyAttributes Attributes 
 		{
			get { return PropertyAttributes.None; } 
		}
		public override bool CanRead
 		{
			get 
 			{
 				if (this.getMethod != null) 
					return true; 
 				else if (this.originalPropertyInfo != null)
					return this.originalPropertyInfo.CanRead; 
				else
					return false;
 			}
		} 
 		public override bool CanWrite
 		{ 
			get 
 			{
				if (this.setMethod != null) 
					return true;
				else if (this.originalPropertyInfo != null)
 					return this.originalPropertyInfo.CanWrite;
				else 
 					return false;
 			} 
		} 
 		public override Type DeclaringType
		{ 
			get { return this.declaringType; }
		}
 		public override Type ReflectedType
		{ 
 			get { return this.declaringType; }
 		} 
		public override object[] GetCustomAttributes(bool inherit) 
 		{
			return new object[0]; 
		}
		public override object[] GetCustomAttributes(Type attributeType, bool inherit)
 		{
			return new object[0]; 
 		}
 		public override bool IsDefined(Type attributeType, bool inherit) 
		{ 
 			throw new NotSupportedException();
		} 
	}
	#endregion

 	#region PathParser 

	internal enum SourceValueType 
 	{ 
 		Property,
		Indexer 
 	};

	internal enum DrillIn
	{ 
		Never,
 		IfNeeded 
	}; 

 	internal struct SourceValueInfo 
 	{
		internal SourceValueType type;
 		internal DrillIn drillIn;
		internal string name; 

		internal SourceValueInfo(SourceValueType t, DrillIn d, string n) 
		{ 
 			type = t;
			drillIn = d; 
 			name = n;
 		}
	}
 
 	internal sealed class PathParser
	{ 
		private string error = string.Empty; 
		private State state;
 		private string pathValue; 
		private int index;
 		private int pathLength;
 		private DrillIn drillIn;
		private List al = new List(); 
 		private const char NullChar = Char.MinValue;
		private static List EmptyInfo = new List(1); 
		private static string SpecialChars = @".[]"; 

		private enum State 
 		{
			Init,
 			Prop,
 			Done 
		};
 
 		internal String Error 
		{
			get 
			{
 				return error;
			}
 		} 

 		internal List Parse(string path, bool returnResultBeforeError) 
		{ 
 			this.pathValue = (path != null) ? path.Trim() : String.Empty;
			this.pathLength = this.pathValue.Length; 
			this.index = 0;
			this.drillIn = DrillIn.IfNeeded;

 			this.al.Clear(); 
			this.error = null;
 			this.state = State.Init; 
 
 			if (this.pathLength > 0 && this.pathValue[0] == '.')
			{ 
 				//empty first prop - > input path was like ".bar"; need to add first empty property
				SourceValueInfo info = new SourceValueInfo(SourceValueType.Property, this.drillIn, string.Empty);
				this.al.Add(info);
			} 

 			while (this.state != State.Done) 
			{ 
 				char c = (this.index < this.pathLength) ? this.pathValue[this.index] : NullChar;
 				switch (this.state) 
				{
 					case State.Init:
						switch (c)
						{ 
							case '/':
 							case '.': 
							case '[': 
 							case NullChar:
 								this.state = State.Prop; 
								break;
 							case ']'://unexpected close indexer, report error
								this.error = "path[" + this.index + "] = " + c;
								return returnResultBeforeError ? this.al : EmptyInfo; 

							default: 
 								AddProperty(); 
								break;
 						} 
 						break;

					case State.Prop:
 						bool isIndexer = false; 
						switch (c)
						{ 
							case '.': 
 								this.drillIn = DrillIn.Never;
								break; 
 							case '[':
 								isIndexer = true;
								break;
 							case NullChar: 
								--this.index;
								break; 
							default: 
 								this.error = "path[" + this.index + "] = " + c;
								return returnResultBeforeError ? this.al : EmptyInfo; 
 						}
 						++this.index;      // skip over special character
						if (isIndexer)
 							AddIndexer(); 
						else
							AddProperty(); 
						break; 
 				}
			} 
 			
 			return (this.error == null || returnResultBeforeError) ? this.al : EmptyInfo;
		}
 
 		private void AddProperty()
		{ 
			int start = this.index; 
			while (this.index < this.pathLength && SpecialChars.IndexOf(this.pathValue[this.index]) < 0)
 				++this.index; 

			string name = this.pathValue.Substring(start, this.index - start).Trim();
 			SourceValueInfo info = new SourceValueInfo(
 										SourceValueType.Property, 
										this.drillIn, name);
 			this.al.Add(info); 
			StartNewLevel(); 
		}
 
		private void AddIndexer()
 		{
			int start = this.index;
 			int level = 1; 
 			while (level > 0)
			{ 
 				if (this.index >= this.pathLength) 
				{
					return; 
				}
 				if (this.pathValue[this.index] == '[')
					++level;
 				else if (this.pathValue[this.index] == ']') 
 					--level;
				++this.index; 
 			} 
			string name = this.pathValue.Substring(start, this.index - start - 1).Trim();
			SourceValueInfo info = new SourceValueInfo( 
										SourceValueType.Indexer,
 										this.drillIn, name);
			this.al.Add(info);
 			StartNewLevel(); 
 		}
 
		private void StartNewLevel() 
 		{
			if (this.index >= this.pathLength) 
				this.state = State.Done;
			this.drillIn = DrillIn.Never;
 		}
	} 

 	#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