public override Type GetChildDataContextType(Type dataContext, Type parentDataContext, RedwoodControl control)
 {
     var type = control.GetType();
     var property = type.GetProperty(PropertyName);
     if (property == null) throw new Exception($"property { PropertyName } does not exists on { type.FullName }.");
     return property.GetValue(control).GetType();
 }
 public static Type GetDataContextType(Type parentDataContext, RedwoodControl control)
 {
     var dataContext = (control as RedwoodBindableControl)?.DataContext?.GetType() ?? parentDataContext;
     var attributes = control.GetType().GetCustomAttributes<DataContextChangeAttribute>();
     foreach (var attribute in attributes)
     {
         dataContext = attribute.GetChildDataContextType(dataContext, parentDataContext, control);
     }
     return dataContext;
 }
示例#3
0
 /// <summary>
 /// Validates the control command.
 /// </summary>
 public void ValidateControlCommand(string[] path, string command, RedwoodControl viewRootControl, RedwoodControl targetControl, ref string validationTargetPath)
 {
     // find the binding
     RedwoodProperty targetProperty;
     var binding = FindControlCommandBinding(path, command, viewRootControl, (RedwoodBindableControl)targetControl, ref validationTargetPath, out targetProperty);
     if (binding == null)
     {
         ThrowEventValidationException();
         return;
     }
 }
        public override Type GetChildDataContextType(Type dataContext, Type parentDataContext, RedwoodControl control)
        {
            if(dataContext.IsArray)
            {
                return dataContext.GetElementType();
            }
            var ienumerable = dataContext.GetInterfaces()
                    .FirstOrDefault(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IEnumerable<>));

            if (ienumerable != null)
            {
                return ienumerable.GetGenericArguments()[0];
            }
            else throw new NotSupportedException();
        }
示例#5
0
        /// <summary>
        /// Validates the command.
        /// </summary>
        public void ValidateCommand(string[] path, string command, RedwoodControl viewRootControl, ref string validationTargetPath)
        {
            // find the binding
            RedwoodProperty targetProperty;
            RedwoodBindableControl targetControl;
            var binding = FindCommandBinding(path, command, viewRootControl, ref validationTargetPath, out targetControl, out targetProperty);
            if (binding == null)
            {
                ThrowEventValidationException();
                return;
            }

            // validate the command against the control
            if (targetControl is IEventValidationHandler)
            {
                if (!((IEventValidationHandler)targetControl).ValidateCommand(targetProperty))
                {
                    ThrowEventValidationException();
                    return;
                }
            }
        }
示例#6
0
        /// <summary>
        /// Finds the binding of the specified type on the specified viewmodel path.
        /// </summary>
        private CommandBindingExpression FindCommandBinding(string[] path, string command, RedwoodControl viewRootControl, ref string validationTargetPath, out RedwoodBindableControl targetControl, out RedwoodProperty targetProperty)
        {
            // walk the control tree and find the path
            CommandBindingExpression result = null;
            RedwoodBindableControl resultControl = null;
            RedwoodProperty resultProperty = null;
            string resultValidationTargetPath = validationTargetPath;

            var walker = new NonEvaluatingControlTreeWalker(viewRootControl);
            walker.ProcessControlTree((ViewModel, control) =>
            {
                // compare path
                if (result == null && control is RedwoodBindableControl && ViewModelPathComparer.AreEqual(path, walker.CurrentPathArray))
                {
                    // find bindings of current control
                    var bindableControl = (RedwoodBindableControl)control;
                    var binding = bindableControl.GetAllBindings().Where(p => p.Value is CommandBindingExpression)
                        .FirstOrDefault(b => b.Value.Expression == command);
                    if (binding.Key != null)
                    {
                        // we have found the binding, now get the validation path
                        var currentValidationTargetPath = KnockoutHelper.GetValidationTargetExpression(bindableControl, true);
                        if (currentValidationTargetPath == resultValidationTargetPath)
                        {
                            // the validation path is equal, we have found the binding
                            result = (CommandBindingExpression)binding.Value;
                            resultControl = bindableControl;
                            resultProperty = binding.Key;
                            resultValidationTargetPath = KnockoutHelper.GetValidationTargetExpression(bindableControl, false);
                        }
                    }
                }
            });

            validationTargetPath = resultValidationTargetPath;
            targetControl = resultControl;
            targetProperty = resultProperty;
            return result;
        }
示例#7
0
 public abstract void CreateControls(RedwoodRequestContext context, RedwoodControl container);
示例#8
0
 /// <summary>
 /// Evaluates the command arguments.
 /// </summary>
 private static object[] EvaluateCommandArguments(object viewModel, RedwoodControl viewRootControl, List<object> hierarchy, InvocationExpressionSyntax node)
 {
     var arguments = node.ArgumentList.Arguments.Select(a =>
     {
         var evaluator = new ExpressionEvaluationVisitor(viewModel, viewRootControl, hierarchy);
         return evaluator.Visit(a);
     }).ToArray();
     return arguments;
 }
示例#9
0
 /// <summary>
 /// Finds the method on control.
 /// </summary>
 private static MethodInfo FindMethodOnControl(RedwoodControl targetControl, InvocationExpressionSyntax node)
 {
     MethodInfo method;
     var methods = targetControl.GetType().GetMethods().Where(m => m.Name == node.Expression.ToString()).ToList();
     if (methods.Count == 0)
     {
         throw new Exception(string.Format("The control '{0}' does not have a function '{1}'!", targetControl.GetType().FullName, node.Expression));
     }
     else if (methods.Count > 1)
     {
         throw new Exception(string.Format("The control '{0}' has more than one function called '{1}'! Overloading in {{controlCommand: ...}} binding is not yet supported!", targetControl.GetType().FullName, node.Expression));
     }
     method = methods[0];
     return method;
 }
示例#10
0
 public void BuildContent(RedwoodRequestContext context, RedwoodControl container)
 {
     var controlBuilderFactory = context.Configuration.ServiceLocator.GetService<IControlBuilderFactory>();
     var control = BuildContentBody(controlBuilderFactory);
     container.Children.Add(control);
 }
 public abstract Type GetChildDataContextType(Type dataContext, Type parentDataContext, RedwoodControl control);
示例#12
0
 public void OnAddedToParent(RedwoodControl parent)
 {
     SetParent(parent);
 }
示例#13
0
 public override void CreateControls(RedwoodRequestContext context, RedwoodControl container)
 {
     ContentTemplate.BuildContent(context, container);
 }
示例#14
0
 /// <summary>
 /// Invokes the specified method on all controls in the page control tree.
 /// </summary>
 private void InvokePageLifeCycleEventRecursive(RedwoodControl control, Action<RedwoodControl> action)
 {
     foreach (var child in control.GetThisAndAllDescendants())
     {
         action(child);
     }
 }
示例#15
0
 /// <summary>
 /// Resolves the command called on the ViewModel.
 /// </summary>
 public ActionInfo GetFunction(RedwoodControl viewRootControl, RedwoodRequestContext context, string[] path, string command)
 {
     return GetFunction(null, viewRootControl, context, path, command);
 }
示例#16
0
 /// <summary>
 /// Translates the binding expression to the knockout command name.
 /// </summary>
 public static string TranslateToKnockoutCommand(RedwoodControl target, RedwoodProperty property, CommandMarkupExpression binding)
 {
     return DataContextPathBuilder.Default.BuildPath(target);
 }
示例#17
0
        /// <summary>
        /// Resolves the command called on the RedwoodControl.
        /// </summary>
        public ActionInfo GetFunction(RedwoodControl targetControl, RedwoodControl viewRootControl, RedwoodRequestContext context, string[] path, string command)
        {
            // event validation
            var validationTargetPath = context.ModelState.ValidationTargetPath;
            if (targetControl == null)
            {
                eventValidator.ValidateCommand(path, command, viewRootControl, ref validationTargetPath);
            }
            else
            {
                eventValidator.ValidateControlCommand(path, command, viewRootControl, targetControl, ref validationTargetPath);
            }

            // resolve the path in the view model
            var viewModel = context.ViewModel;
            List<object> hierarchy = ResolveViewModelPath(viewModel, viewRootControl, path);

            // resolve validation target
            if (!string.IsNullOrEmpty(validationTargetPath))
            {
                var hierarchyCopy = new List<object>(hierarchy);
                context.ModelState.ValidationTarget = EvaluateOnViewModel(viewModel, viewRootControl, hierarchyCopy, validationTargetPath);
            }

            // find the function
            var tree = CSharpSyntaxTree.ParseText(command, new CSharpParseOptions(LanguageVersion.CSharp5, DocumentationMode.Parse, SourceCodeKind.Interactive));
            var expr = tree.EnsureSingleExpression();
            var node = expr.ChildNodes().First() as InvocationExpressionSyntax;
            if (node == null)
            {
                throw new ParserException("The expression in {command: ...} binding must be a method call!");
            }
            MethodInfo method;
            object target;
            if (targetControl != null)
            {
                // the function is invoked on the control object
                method = FindMethodOnControl(targetControl, node);
                target = targetControl;
            }
            else
            {
                // the function is invoked on the viewmodel
                method = FindMethodOnViewModel(viewModel, viewRootControl, hierarchy, node, out target);
            }

            // validate that we can safely call the method
            ValidateMethod(method);

            // parse arguments
            var arguments = EvaluateCommandArguments(viewModel, viewRootControl, hierarchy, node);

            // return the delegate for further invoke
            return new ActionInfo()
            {
                IsControlCommand = target != null,
                Target = target,
                MethodInfo = method,
                Arguments = method.GetParameters().Select((param, index) => new ActionParameterInfo()
                {
                    ParameterInfo = param,
                    Value = arguments[index]
                }).ToArray()
            };
        }
示例#18
0
        /// <summary>
        /// Resolves the path in the view model and returns the target object.
        /// </summary>
        private List<object> ResolveViewModelPath(object viewModel, RedwoodControl viewRootControl, string[] path)
        {
            var visitor = new ExpressionEvaluationVisitor(viewModel, viewRootControl);

            var outputHierarchy = new List<object>();
            outputHierarchy.Add(viewModel);
            foreach (var expression in path)
            {
                // evaluate path fragment
                var pathTree = CSharpSyntaxTree.ParseText(expression, new CSharpParseOptions(LanguageVersion.CSharp5, DocumentationMode.Parse, SourceCodeKind.Interactive));
                var pathExpr = pathTree.EnsureSingleExpression();

                var result = visitor.Visit(pathExpr);
                visitor.BackupCurrentPosition(result, expression);
                outputHierarchy.Add(result);
            }
            return outputHierarchy;
        }
示例#19
0
        /// <summary>
        /// Evaluates the expression the on view model with specified hierarchy.
        /// </summary>
        private object EvaluateOnViewModel(object viewModel, RedwoodControl viewRootControl, List<object> hierarchy, string expression)
        {
            var pathTree = CSharpSyntaxTree.ParseText(expression, new CSharpParseOptions(LanguageVersion.CSharp5, DocumentationMode.Parse, SourceCodeKind.Interactive));
            var pathExpr = pathTree.EnsureSingleExpression();

            var visitor = new ExpressionEvaluationVisitor(viewModel, viewRootControl, hierarchy);
            return visitor.Visit(pathExpr);
        }
示例#20
0
 /// <summary>
 /// Finds the method on view model.
 /// </summary>
 private static MethodInfo FindMethodOnViewModel(object viewModel, RedwoodControl viewRootControl, List<object> hierarchy, InvocationExpressionSyntax node, out object target)
 {
     MethodInfo method;
     var methodEvaluator = new ExpressionEvaluationVisitor(viewModel, viewRootControl, hierarchy)
     {
         AllowMethods = true
     };
     method = methodEvaluator.Visit(node.Expression) as MethodInfo;
     if (method == null)
     {
         throw new Exception("The command path was not found!");
     }
     target = methodEvaluator.MethodInvocationTarget;
     return method;
 }