/Signum.Windows/Fluent/FrameworkFactoryGenerator.cs
C# | 217 lines | 165 code | 50 blank | 2 comment | 41 complexity | 33ca88c1dc4f0ea96ed0dd52013daaf0 MD5 | raw file
Possible License(s): LGPL-3.0
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using System.Linq.Expressions;
- using w = System.Windows;
- using Signum.Utilities;
- using Signum.Utilities.Reflection;
- using System.Reflection;
- using System.Windows.Controls;
- using Signum.Utilities.ExpressionTrees;
- using System.ComponentModel;
- using System.Windows.Data;
- using System.Windows.Markup;
-
- namespace Signum.Windows
- {
- static class FrameworkElementFactoryGenerator
- {
- public static w.FrameworkElementFactory Generate(Expression<Func<w.FrameworkElement>> expression)
- {
- ParameterExpression rootFactory = Expression.Parameter(typeof(w.FrameworkElementFactory), "f");
- var list = Process(expression.Body, rootFactory);
- var variables = list.Where(a => a.NodeType == ExpressionType.Assign).Select(e => (ParameterExpression)((BinaryExpression)e).Left);
- list.Add(rootFactory);
-
- var lambda = Expression.Lambda<Func<w.FrameworkElementFactory>>(
- Expression.Block(variables, list));
-
- return lambda.Compile()();
- }
-
- static ConstructorInfo ci = ReflectionTools.GetConstuctorInfo(() => new w.FrameworkElementFactory(typeof(Border)));
- static MethodInfo miAddHandler = ReflectionTools.GetMethodInfo((w.FrameworkElementFactory fef) => fef.AddHandler(null, null));
- static MethodInfo miRemoveHandler = ReflectionTools.GetMethodInfo((w.FrameworkElementFactory fef) => fef.RemoveHandler(null, null));
- static MethodInfo miSetBinding = ReflectionTools.GetMethodInfo((w.FrameworkElementFactory fef) => fef.SetBinding(null, null));
- static MethodInfo miSetValue = ReflectionTools.GetMethodInfo((w.FrameworkElementFactory fef) => fef.SetValue(null, null));
- static MethodInfo miSetResourceReference = ReflectionTools.GetMethodInfo((w.FrameworkElementFactory fef) => fef.SetResourceReference(null, null));
- static MethodInfo miAppendChild = ReflectionTools.GetMethodInfo((w.FrameworkElementFactory fef) => fef.AppendChild(null));
-
- static List<Expression> Process(Expression expression, ParameterExpression factory)
- {
- if (expression.NodeType == ExpressionType.New)
- {
- if(((NewExpression)expression).Arguments.Any())
- throw new InvalidOperationException("No arguments in constructo allowed");
-
- return new List<Expression>
- {
- Expression.Assign(factory, Expression.New(ci, Expression.Constant(expression.Type)))
- };
- }
-
- if(expression.NodeType == ExpressionType.MemberInit)
- {
- MemberInitExpression mie = (MemberInitExpression)expression;
- var list = Process(mie.NewExpression, factory);
-
- foreach (MemberBinding mb in mie.Bindings)
- {
- switch (mb.BindingType)
- {
- case MemberBindingType.Assignment:
- {
- MemberAssignment ma = (MemberAssignment)mb;
-
- PropertyInfo pi = ma.Member as PropertyInfo;
-
- if (IsDefaultMember(pi))
- list.AddRange(ProcessChild(ma.Expression, factory));
- else
- {
- DependencyPropertyDescriptor desc = DependencyPropertyDescriptor.FromName(pi.Name, pi.DeclaringType, pi.DeclaringType);
- if (desc == null)
- throw new InvalidOperationException("{0} is not a DependencyProperty".Formato(pi.PropertyName()));
-
- list.Add(Expression.Call(factory, miSetValue, Expression.Constant(desc.DependencyProperty), Expression.Convert(ma.Expression, typeof(object))));
- }
- }break;
- case MemberBindingType.ListBinding:
- {
- MemberListBinding bindings = (MemberListBinding)mb;
-
- DefaultMemberAttribute dma = bindings.Member.DeclaringType.SingleAttribute<DefaultMemberAttribute>();
-
- //if(!IsDefaultMember(bindings.Member))
- // throw new InvalidOperationException("Add items only work for the DefaultMember");
-
- foreach (var item in bindings.Initializers)
- {
- if(item.Arguments.Count != 1)
- throw new InvalidOperationException("Add Method {0} not supported".Formato(item.AddMethod.MethodName()));
-
- list.AddRange(ProcessChild(item.Arguments.SingleEx(), factory));
- }
-
- }break;
- case MemberBindingType.MemberBinding:
- throw new InvalidOperationException("MemberBinding not supported");
- }
- }
-
- return list;
- }
-
- if (expression.NodeType == ExpressionType.Call)
- {
- MethodCallExpression call = (MethodCallExpression)expression;
-
- MethodInfo mi = call.Method;
-
- if (mi.DeclaringType != typeof(Fluent) || mi.ReturnType != mi.GetParameters()[0].ParameterType)
- throw new InvalidOperationException("Method {0} not supported".Formato(mi.MethodName()));
-
- var list = Process(call.Arguments[0], factory);
-
- list.Add(ProcessMethod(factory, call));
-
- return list;
- }
-
- if (expression.NodeType == ExpressionType.Convert)
- {
- return Process(((UnaryExpression)expression).Operand, factory);
- }
-
- throw new InvalidOperationException("Expression {0} not supported");
- }
-
- private static List<Expression> ProcessChild(Expression single, ParameterExpression factory)
- {
- if (!typeof(w.FrameworkElement).IsAssignableFrom(single.Type) && !typeof(w.FrameworkContentElement).IsAssignableFrom(single.Type))
- throw new InvalidOperationException("Can not make a {0} from a {1}".Formato(typeof(w.FrameworkElementFactory).Name, single.Type));
-
- ParameterExpression newFactory = Expression.Parameter(typeof(w.FrameworkElementFactory));
- var list = Process(single, newFactory);
- list.Add(Expression.Call(factory, miAppendChild, newFactory));
- return list;
- }
-
- private static bool IsDefaultMember(MemberInfo mi)
- {
- var dma = mi.DeclaringType.SingleAttribute<ContentPropertyAttribute>();
- return dma != null && dma.Name == mi.Name;
- }
-
- static Expression ProcessMethod(ParameterExpression factory, MethodCallExpression call)
- {
- switch (call.Method.Name)
- {
- case "Set": return Expression.Call(factory, miSetValue, call.Arguments[1], call.Arguments[2]);
- case "Hide": return Expression.Call(factory, miSetValue, Expression.Constant(w.UIElement.VisibilityProperty), Expression.Constant(w.Visibility.Hidden));
- case "Collapse": return Expression.Call(factory, miSetValue, Expression.Constant(w.UIElement.VisibilityProperty), Expression.Constant(w.Visibility.Collapsed));
- case "Visible": return Expression.Call(factory, miSetValue, Expression.Constant(w.UIElement.VisibilityProperty), Expression.Constant(w.Visibility.Visible));
- case "ReadOnly": return Expression.Call(factory, miSetValue, Expression.Constant(Common.IsReadOnlyProperty), Expression.Constant(true));
- case "Editable": return Expression.Call(factory, miSetValue, Expression.Constant(Common.IsReadOnlyProperty), Expression.Constant(false));
-
- case "Handle": return Expression.Call(factory, miAddHandler, call.Arguments[1], Expression.Convert(call.Arguments[2], typeof(Delegate)));
- case "ResourceReference": return Expression.Call(factory, miSetResourceReference, call.Arguments[1], call.Arguments[2]);
-
- case "Bind": return Expression.Call(factory, miSetBinding, call.Arguments[1], GetBinding(call.Method.GetGenericArguments().Length == 2, call.Arguments.Skip(2).ToArray()));
- }
-
- throw new InvalidOperationException("Methods {0} not supported".Formato(call.Method.Name));
- }
-
- static ConstructorInfo ciBinding = ReflectionTools.GetConstuctorInfo(() => new Binding(""));
- static PropertyInfo ciSource = ReflectionTools.GetPropertyInfo((Binding b) => b.Source);
- static PropertyInfo ciConverter = ReflectionTools.GetPropertyInfo((Binding b) => b.Converter);
-
- static Expression GetBinding(bool hasExpression, Expression[] expression)
- {
- if (typeof(BindingBase).IsAssignableFrom(expression[0].Type))
- return expression[0];
-
- bool noSource = hasExpression? typeof(LambdaExpression).IsAssignableFrom(expression[0].Type) :
- typeof(string).IsAssignableFrom(expression[0].Type);
-
- Expression path = hasExpression? (noSource ? GetPathConstant(expression[0]): GetPathConstant(expression[1])):
- (noSource ? expression[0]: expression[1]);
-
-
- Expression source = noSource? null: expression[0];
-
- Expression converter = expression.Length == (noSource? 2:3) ? expression.Last(): null;
-
- NewExpression newExpr = Expression.New(ciBinding, path);
-
- if (source == null && converter == null)
- return newExpr;
-
- List<MemberBinding> binding = new List<MemberBinding>();
- if (source != null)
- binding.Add(Expression.Bind(ciSource, source));
-
- if (converter != null)
- binding.Add(Expression.Bind(ciConverter, converter));
-
-
- return Expression.MemberInit(newExpr, binding);
-
- }
-
- static ConstantExpression GetPathConstant(Expression expression)
- {
- if (expression.NodeType == ExpressionType.Quote)
- expression = ((UnaryExpression)expression).Operand;
-
- if (expression.NodeType != ExpressionType.Lambda)
- throw new InvalidOperationException();
-
- string str = RouteVisitor.GetRoute((LambdaExpression)expression);
-
- return Expression.Constant(str);
- }
- }
- }