/// <summary> /// Updates the relative source value. /// </summary> public void UpdateSource([NotNull] object target) { if (target == null) { throw BindingExceptionManager.InvalidBindingTarget(RelativeSourceNode.Path); } var path = RelativeSourceNode.Path ?? String.Empty; if (!String.IsNullOrEmpty(Path)) { path = BindingExtensions.MergePath(path, Path); } if (RelativeSourceNode.Type != RelativeSourceExpressionNode.SelfType) { if (RelativeSourceNode.Type == RelativeSourceExpressionNode.MemberSourceType) { target = BindingServiceProvider.ContextManager.GetBindingContext(target); } else { target = new ParentSourceValue(target, RelativeSourceNode); } } IObserver observer = BindingServiceProvider.ObserverProvider.Observe(target, BindingPath.Create(path), false); _bindingSource = new BindingSource(observer); }
private IExpressionNode GetResourceMember(IExpressionNode node, string memberName, IList <IExpressionNode> nodes) { IExpressionNode staticValue; if (_staticNodes.TryGetValue(node, out staticValue)) { return(staticValue); } IBindingPath path = BindingServiceProvider.BindingPathFactory(memberName); string firstMember = path.Parts[0]; Type type = BindingServiceProvider.ResourceResolver.ResolveType(firstMember, Context, false); var resourceMember = (ResourceExpressionNode)nodes[0]; if (resourceMember.Dynamic && type == null) { memberName = BindingExtensions.MergePath(path.Parts.Skip(1).ToArray()); return(GetOrAddBindingMember("$" + path.Path, (s, i) => new BindingMemberExpressionNode(firstMember, memberName, s, i))); } bool dynamicMember = false; IExpressionNode firstMemberNode = nodes[1]; if (!_staticNodes.TryGetValue(firstMemberNode, out staticValue)) { if (type == null) { var value = BindingServiceProvider .ResourceResolver .ResolveObject(firstMember, Context, true) .Value; var dynamicObject = value as IDynamicObject; if (dynamicObject == null || path.Parts.Count <= 1) { staticValue = new ConstantExpressionNode(value); } else { staticValue = new ConstantExpressionNode(dynamicObject.GetMember(path.Parts[1], Empty.Array <object>())); dynamicMember = true; } } else { staticValue = new ConstantExpressionNode(type, typeof(Type)); } _staticNodes[firstMemberNode] = staticValue; if (dynamicMember) { _staticNodes[nodes[2]] = staticValue; } } if (firstMemberNode == node || (dynamicMember && node == nodes[2])) { return(staticValue); } return(node); }
public void MergePath(string path) { _path = BindingExtensions.MergePath(_path, path); }
public IExpressionNode Visit(IExpressionNode node) { var member = node as IMemberExpressionNode; var resourceExpressionNode = member?.Target as ResourceExpressionNode; if (resourceExpressionNode != null) { //$self, $this --> $BindingServiceProvider.ResourceResolver.SelfResourceName if (member.Member == "self" || member.Member == "this") { if (resourceExpressionNode.Dynamic) { return(new MemberExpressionNode(member.Target, BindingServiceProvider.ResourceResolver.SelfResourceName)); } return(new MethodCallExpressionNode(member.Target, DefaultBindingParserHandler.GetSelfMethod, null, null)); } //$context --> $BindingServiceProvider.ResourceResolver.DataContextResourceName if (member.Member == "context") { return(new MemberExpressionNode(member.Target, BindingServiceProvider.ResourceResolver.DataContextResourceName)); } //$args, $arg --> $GetEventArgs() if (member.Member == "args" || member.Member == "arg") { return(new MethodCallExpressionNode(member.Target, DefaultBindingParserHandler.GetEventArgsMethod, null, null)); } //$binding --> $GetBinding() if (member.Member == "binding") { return(new MethodCallExpressionNode(member.Target, DefaultBindingParserHandler.GetBindingMethod, null, null)); } } var methodCallExp = node as IMethodCallExpressionNode; if (methodCallExp != null && methodCallExp.Target is ResourceExpressionNode) { //$OneTime(Expression) --> oneTimeImpl.GetValue(GetBinding(), () => Expression) if (methodCallExp.Method == "OneTime" && methodCallExp.Arguments.Count == 1) { DataConstant <object> constant = Guid.NewGuid().ToString("n"); var idEx = new ConstantExpressionNode(constant); var getBindEx = new MethodCallExpressionNode(ResourceExpressionNode.DynamicInstance, DefaultBindingParserHandler.GetBindingMethod, null, null); IExpressionNode getValueEx = new LambdaExpressionNode(methodCallExp.Arguments[0], null); return(new MethodCallExpressionNode(new ConstantExpressionNode(typeof(BindingExtensions)), "GetOrAddValue", new[] { getBindEx, idEx, getValueEx }, null).Accept(this)); } //Alias ($Format(), $MethodName, etc) --> type.Format() Type type; string method; if (BindingServiceProvider.ResourceResolver.TryGetMethodAlias(methodCallExp.Method, out type, out method)) { return(new MethodCallExpressionNode(new ConstantExpressionNode(type), method, methodCallExp.Arguments, methodCallExp.TypeArgs).Accept(this)); } } var nodes = new List <IExpressionNode>(); var members = new List <string>(); string memberName = node.TryGetMemberName(true, true, nodes, members); if (memberName == null) { var relativeExp = nodes[0] as IRelativeSourceExpressionNode; if (relativeExp != null) { relativeExp.MergePath(BindingExtensions.MergePath(members)); return(relativeExp); } var methodCall = nodes[0] as IMethodCallExpressionNode; if (methodCall != null && methodCall.Target is ResourceExpressionNode) { if (RelativeSourceAliases.Contains(methodCall.Method)) { if ((methodCall.Arguments.Count == 1 || methodCall.Arguments.Count == 2) && methodCall.Arguments[0] is IMemberExpressionNode) { int level = 1; var relativeType = (IMemberExpressionNode)methodCall.Arguments[0]; if (methodCall.Arguments.Count == 2) { level = (int)((IConstantExpressionNode)methodCall.Arguments[1]).Value; } return(RelativeSourceExpressionNode.CreateRelativeSource(relativeType.Member, (uint)level, BindingExtensions.MergePath(members))); } } if (ElementSourceAliases.Contains(methodCall.Method)) { if (methodCall.Arguments.Count == 1 && methodCall.Arguments[0] is IMemberExpressionNode) { var elementSource = (IMemberExpressionNode)methodCall.Arguments[0]; return(RelativeSourceExpressionNode.CreateElementSource(elementSource.Member, BindingExtensions.MergePath(members))); } } } } return(node); }
public static Expression ProvideExpression(IBuilderSyntaxContext context) { var mExp = context.MethodExpression; var name = mExp.Method.Name; if (name == nameof(EventArgs)) { if (context.IsSameExpression()) { return(Expression.Convert(Expression.Call(GetEventArgsMethod, context.ContextParameter), mExp.Method.ReturnType)); } return(null); } if (name == nameof(Binding)) { if (context.IsSameExpression()) { return(Expression.Convert(Expression.Call(GetBindingMethod, context.ContextParameter), mExp.Method.ReturnType)); } return(null); } if (name == nameof(ResourceMethod)) { if (!context.IsSameExpression()) { return(null); } var typeArgsEx = Expression.NewArrayInit(typeof(Type), Expression.Constant(mExp.Method.ReturnType, typeof(Type))); return(Expression.Convert(Expression.Call(ResourceMethodImplMethod, mExp.Arguments[1], typeArgsEx, context.ContextParameter, mExp.Arguments[2]), context.Expression.Type)); } if (name == nameof(OneTime)) { if (!context.IsSameExpression()) { return(null); } DataConstant <object> id = Guid.NewGuid().ToString("n"); var idEx = Expression.Constant(id); var getBindEx = Expression.Call(GetBindingMethod, context.ContextParameter); var valueEx = Expression.Lambda(mExp.Arguments[1], Empty.Array <ParameterExpression>()); var method = GetOneTimeValueMethod.MakeGenericMethod(mExp.Arguments[1].Type); return(Expression.Call(method, new Expression[] { getBindEx, idEx, valueEx })); } if (name == nameof(GetErrors)) { if (!context.IsSameExpression()) { return(null); } var id = Guid.NewGuid(); var args = new List <Expression>(); var members = new List <string>(); var arrayExpression = mExp.Arguments[1] as NewArrayExpression; if (arrayExpression != null) { for (int i = 0; i < arrayExpression.Expressions.Count; i++) { var constantExpression = arrayExpression.Expressions[i] as ConstantExpression; if (constantExpression == null) { args.Add(arrayExpression.Expressions[i]); } else { members.Add((string)constantExpression.Value); } } } if (args.Count == 0) { args.Add(Expression.Call(ResourceMethodInfo.MakeGenericMethod(typeof(object)), Expression.Constant(null, typeof(IBindingSyntaxContext)), Expression.Constant(BindingServiceProvider.ResourceResolver.BindingSourceResourceName))); } context.AddBuildCallback(builder => { var behaviors = builder.GetOrAddBehaviors(); if (!behaviors.Any(behavior => behavior is NotifyDataErrorsAggregatorBehavior)) { behaviors.Clear(); behaviors.Add(new OneTimeBindingMode(false)); } behaviors.Add(new NotifyDataErrorsAggregatorBehavior(id) { ErrorPaths = members.ToArray() }); }); var array = Expression.NewArrayInit(typeof(object), args.Select(e => ExpressionReflectionManager.ConvertIfNeed(e, typeof(object), false))); return(Expression.Call(GetErrorsMethod, Expression.Constant(id), context.ContextParameter, array)); } Expression lastExpression; string path = string.Empty; if (!context.IsSameExpression() && !BindingExtensions.TryGetMemberPath(context.Expression, ".", false, out lastExpression, out path) && lastExpression != mExp) { return(null); } if (name == AttachedMemberConstants.DataContext) { return(context.GetOrAddParameterExpression(string.Empty, path, context.Expression, (dataContext, s) => BindingExtensions.CreateBindingSource(dataContext, s, null, true))); } if (name == nameof(Self) || name == nameof(Root) || name == nameof(Resource) || name == nameof(Source)) { string resourceName; switch (name) { case nameof(Self): resourceName = BindingServiceProvider.ResourceResolver.SelfResourceName; break; case nameof(Root): resourceName = BindingServiceProvider.ResourceResolver.RootElementResourceName; break; case nameof(Source): resourceName = BindingServiceProvider.ResourceResolver.BindingSourceResourceName; break; case nameof(Resource): mExp.Arguments[1].TryGetStaticValue(out resourceName, true); if (mExp.Arguments.Count == 3) { #pragma warning disable 618 LambdaExpression lambda = mExp.Arguments[2] as LambdaExpression; if (lambda == null) { lambda = (LambdaExpression)((UnaryExpression)mExp.Arguments[2]).Operand; } path = BindingExtensions.MergePath(lambda.GetMemberInfo().Name, path); #pragma warning restore 618 } break; default: mExp.Arguments[1].TryGetStaticValue(out resourceName, true); break; } return(context.GetOrAddParameterExpression("res:" + resourceName, path, context.Expression, (dataContext, s) => { var value = BindingServiceProvider .ResourceResolver .ResolveObject(resourceName, dataContext, true); return BindingExtensions.CreateBindingSource(dataContext, s, value); })); } if (name == nameof(Relative) || name == nameof(Element)) { object firstArg; if (mExp.Arguments.Count == 1) { firstArg = FirstLevelBoxed; } else { mExp.Arguments[1].TryGetStaticValue(out firstArg, true); } var relSource = name == nameof(Relative) ? new RelativeSourceInfo(mExp.Method.ReturnType.AssemblyQualifiedName, null, null, (uint)firstArg) : new RelativeSourceInfo(RelativeSourceInfo.ElementSourceType, firstArg.ToString(), null, 0); return(context .GetOrAddParameterExpression(name + mExp.Method.ReturnType.FullName, path, context.Expression, (dataContext, s) => BindingExtensions.CreateBindingSource(relSource, dataContext, dataContext.GetData(BindingBuilderConstants.Target), s))); } return(null); }
public IExpressionNode Visit(IExpressionNode node) { var member = node as IMemberExpressionNode; if (member != null && member.Target is ResourceExpressionNode) { //$self, $this --> $BindingServiceProvider.ResourceResolver.SelfResourceName if (member.Member == "self" || member.Member == "this") { return(new MemberExpressionNode(member.Target, BindingServiceProvider.ResourceResolver.SelfResourceName)); } //$context --> $BindingServiceProvider.ResourceResolver.DataContextResourceName if (member.Member == "context") { return(new MemberExpressionNode(member.Target, BindingServiceProvider.ResourceResolver.DataContextResourceName)); } //$args, $arg --> $GetEventArgs() if (member.Member == "args" || member.Member == "arg") { return(new MethodCallExpressionNode(member.Target, DefaultBindingParserHandler.GetEventArgsMethod, Empty.Array <IExpressionNode>(), Empty.Array <string>())); } } var methodCallExp = node as IMethodCallExpressionNode; if (methodCallExp != null && methodCallExp.Target is ResourceExpressionNode) { //$Format() --> string.Format() if (methodCallExp.Method == "Format") { return(new MethodCallExpressionNode(new ConstantExpressionNode(typeof(string)), methodCallExp.Method, methodCallExp.Arguments, methodCallExp.TypeArgs)); } //$OneTime(Expression) --> oneTimeImpl.GetValue(() => Expression) if (methodCallExp.Method == "OneTime" && methodCallExp.Arguments.Count == 1) { var item = new ConstantExpressionNode(new OneTimeImpl()); IExpressionNode parameter = new LambdaExpressionNode(methodCallExp.Arguments[0], null); return(new MethodCallExpressionNode(item, OneTimeImpl.GetValueMethodName, new[] { parameter }, null)); } } var nodes = new List <IExpressionNode>(); var members = new List <string>(); string memberName = node.TryGetMemberName(true, true, nodes, members); if (memberName == null) { var relativeExp = nodes[0] as IRelativeSourceExpressionNode; if (relativeExp != null) { relativeExp.MergePath(BindingExtensions.MergePath(members)); return(relativeExp); } var methodCall = nodes[0] as IMethodCallExpressionNode; if (methodCall != null && methodCall.Target is ResourceExpressionNode) { if (RelativeSourceAliases.Contains(methodCall.Method)) { if ((methodCall.Arguments.Count == 1 || methodCall.Arguments.Count == 2) && methodCall.Arguments[0] is IMemberExpressionNode) { int level = 1; var relativeType = (IMemberExpressionNode)methodCall.Arguments[0]; if (methodCall.Arguments.Count == 2) { level = (int)((IConstantExpressionNode)methodCall.Arguments[1]).Value; } return(RelativeSourceExpressionNode.CreateRelativeSource(relativeType.Member, (uint)level, BindingExtensions.MergePath(members))); } } if (ElementSourceAliases.Contains(methodCall.Method)) { if (methodCall.Arguments.Count == 1 && methodCall.Arguments[0] is IMemberExpressionNode) { var elementSource = (IMemberExpressionNode)methodCall.Arguments[0]; return(RelativeSourceExpressionNode.CreateElementSource(elementSource.Member, BindingExtensions.MergePath(members))); } } } } return(node); }