/// <summary> /// Creates the HTML object for each property that is part of the parent. /// </summary> /// <param name="context">The context.</param> /// <param name="attribute">The attribute.</param> /// <param name="nativeAttributes">The native attributes.</param> /// <returns>The expressions needed to create the list</returns> private IEnumerable <Expression> CreateWinControlObject(ControlBuilderContext context, ControlLocatorAttribute attribute, IEnumerable nativeAttributes) { var buildElement = context.CurrentControl ?? context.Window; var objectType = this.GetPropertyProxyType(buildElement.Type); var propConstructor = this.GetConstructor(objectType, context); if (propConstructor == null) { throw this.CreateConstructorException(buildElement.Name, objectType); } var itemVariable = buildElement.Expression; return(new[] { (Expression)Expression.Assign(itemVariable, Expression.New(propConstructor.Item1, propConstructor.Item2)), Expression.Call( Expression.Constant(this), this.assignMethodInfo, Expression.Convert(itemVariable, typeof(TControl)), Expression.Constant(attribute, typeof(ControlLocatorAttribute)), Expression.Constant(nativeAttributes, typeof(object[]))) }); }
/// <summary> /// Creates the new item expression that creates the object and initial mapping. /// </summary> /// <param name="controlType">Type of the control.</param> /// <returns>The initial creation lambda expression.</returns> /// <exception cref="System.InvalidOperationException">Thrown if the constructor is invalid.</exception> private Expression <Func <TParent, TApplication, Action <TOutput>, TOutput> > CreateNewItemExpression(Type controlType) { var applicationParameter = Expression.Parameter(typeof(TApplication), "application"); var applicationArgument = new ExpressionData(applicationParameter, typeof(TApplication), "application"); var parentParameter = Expression.Parameter(typeof(TParent), "parent"); var parentArgument = new ExpressionData(parentParameter, typeof(TParent), "rootContext"); var controlVariable = Expression.Variable(controlType); var controlData = new ExpressionData(controlVariable, controlType, controlType.Name); var context = new ControlBuilderContext(applicationArgument, parentArgument, controlData); var constructor = this.GetConstructor(controlType, context); if (constructor == null) { throw this.CreateConstructorException(null, controlType); } var actionParameter = Expression.Parameter(typeof(Action <TOutput>), "action"); // Spin though properties and make an initializer for anything we can set that has an attribute var pageMethodInfo = new Action <TOutput, Action <TOutput> >(this.AssignWindowAttributes).GetMethodInfo(); var expressions = new List <Expression> { Expression.Assign(controlVariable, Expression.New(constructor.Item1, constructor.Item2)), Expression.Call( Expression.Constant(this), pageMethodInfo, Expression.Convert(controlVariable, typeof(TOutput)), actionParameter) }; this.MapObjectProperties(expressions, controlType, context); expressions.Add(controlVariable); var methodCall = Expression.Block(new[] { controlVariable }, expressions); return(Expression.Lambda <Func <TParent, TApplication, Action <TOutput>, TOutput> >(methodCall, parentParameter, applicationParameter, actionParameter)); }
/// <summary> /// Maps the object properties for the given object. /// </summary> /// <param name="expressions">The parent expression list.</param> /// <param name="objectType">Type of the object.</param> /// <param name="context">The window builder context.</param> private void MapObjectProperties(ICollection <Expression> expressions, Type objectType, ControlBuilderContext context) { // ReSharper disable LoopCanBeConvertedToQuery foreach (var propertyInfo in objectType.GetProperties().Where(p => p.SetMethod != null && p.CanWrite && p.PropertyType.IsSupportedPropertyType(typeof(TControl)))) { var propertyType = propertyInfo.PropertyType; var attribute = propertyInfo.GetCustomAttributes(typeof(ControlLocatorAttribute), false).FirstOrDefault() as ControlLocatorAttribute; var customAttributes = this.GetCustomAttributes(propertyInfo); if (attribute == null && customAttributes.Length == 0) { continue; } // Final Properties var itemVariable = Expression.Variable(propertyType); context.CurrentControl = new ExpressionData(itemVariable, propertyType, propertyInfo.Name); var variableList = new List <ParameterExpression> { itemVariable }; var propertyExpressions = new List <Expression>(); // New up property and then check it for inner properties. var childContext = context.CreateChildContext(context.CurrentControl); propertyExpressions.AddRange(this.CreateWinControlObject(childContext, attribute, customAttributes)); this.MapObjectProperties(propertyExpressions, propertyType, childContext); propertyExpressions.Add(Expression.Assign(Expression.Property(context.Window.Expression, propertyInfo), itemVariable)); expressions.Add(Expression.Block(variableList, propertyExpressions)); } }
/// <summary> /// Gets the constructor. /// </summary> /// <param name="itemType">Type of the item.</param> /// <param name="context">The window builder context.</param> /// <returns>The constructor information that matches.</returns> private Tuple <ConstructorInfo, IEnumerable <Expression> > GetConstructor(Type itemType, ControlBuilderContext context) { ConstructorInfo emptyConstructor = null; foreach (var constructorInfo in itemType .GetConstructors(BindingFlags.CreateInstance | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) .OrderByDescending(c => c.GetParameters().Length)) { var parameters = constructorInfo.GetParameters(); if (parameters.Length == 0) { emptyConstructor = constructorInfo; continue; } var slots = new Expression[parameters.Length]; slots.Initialize(); for (var i = 0; i < parameters.Length; i++) { var parameter = parameters[i]; var parameterType = parameter.ParameterType; if (context.Window.Type.IsAssignableFrom(parameterType)) { slots[i] = Expression.Convert(context.Window.Expression, context.Window.Type); } else { slots[i] = this.FillConstructorParameter(parameterType, context.ParentControl, context.RootLocator); } } if (slots.All(s => s != null)) { return(new Tuple <ConstructorInfo, IEnumerable <Expression> >(constructorInfo, slots)); } } return(this.AllowEmptyConstructor && emptyConstructor != null ? new Tuple <ConstructorInfo, IEnumerable <Expression> >(emptyConstructor, new List <Expression>(0)) : null); }