/// <summary> /// Evaluates the specified expression in the context of specified control. /// </summary> public object Evaluate(ValueBindingExpression expression, DotvvmProperty property, DotvvmBindableControl contextControl) { var visitor = EvaluateDataContextPath(contextControl); // evaluate the final expression EvaluateBinding(visitor, expression.Expression, expression.GetViewModelPathExpression(contextControl, property)); return visitor.Result; }
/// <summary> /// Gets the view model path expression. /// </summary> public override string GetViewModelPathExpression(DotvvmBindableControl control, DotvvmProperty property) { // find the parent markup control and calculate number of DataContext changes int numberOfDataContextChanges; var current = control.GetClosestControlBindingTarget(out numberOfDataContextChanges) as DotvvmBindableControl; current.EnsureControlHasId(); return string.Join(".", Enumerable.Range(0, numberOfDataContextChanges).Select(i => "_parent").Concat(new[] { "_controlState_" + current.ID, Expression })); }
/// <summary> /// Gets all data context on the path to root /// </summary> public static object[] GetDataContexts(DotvvmBindableControl contextControl, bool seeThis) { var context = seeThis ? contextControl.GetValue(DotvvmBindableControl.DataContextProperty, false) : null; return (context == null ? new object[0] : new[] { context }) .Concat(contextControl.GetAllAncestors().OfType<DotvvmBindableControl>() .Where(c => c.properties.ContainsKey(DotvvmBindableControl.DataContextProperty)) .Select(c => c.GetValue(DotvvmBindableControl.DataContextProperty, false))) .ToArray(); }
/// <summary> /// Translates the expression to client script. /// </summary> public override string TranslateToClientScript(DotvvmBindableControl control, DotvvmProperty property) { ValidateExpression(Expression); // find the parent markup control and calculate number of DataContext changes int numberOfDataContextChanges; var current = control.GetClosestControlBindingTarget(out numberOfDataContextChanges) as DotvvmBindableControl; current.EnsureControlHasId(); return string.Join(".", Enumerable.Range(0, numberOfDataContextChanges).Select(i => "$parent").Concat(new[] { "$controlState()", current.ID + "()", Expression })); }
public void Add(string name, DotvvmBindableControl control, DotvvmProperty property, Action nullBindingAction) { var binding = control.GetValueBinding(property); if (binding == null) { nullBindingAction(); } else { info.Add(new KnockoutBindingInfo() { Name = name, Expression = control.GetValueBinding(property).GetKnockoutBindingExpression() }); } }
protected object ExecDelegate(DotvvmBindableControl contextControl, bool seeThis, bool setRootControl = false) { var dataContexts = GetDataContexts(contextControl, seeThis); var control = setRootControl ? GetRootControl(contextControl) : null; try { return Delegate(dataContexts, control); } catch (NullReferenceException) { return null; } }
/// <summary> /// Evaluates the specified expression. /// </summary> public override object Evaluate(DotvvmBindableControl control, DotvvmProperty property) { ValidateExpression(Expression); // find the parent markup control and calculate number of DataContext changes int numberOfDataContextChanges; var current = control.GetClosestControlBindingTarget(out numberOfDataContextChanges) as DotvvmBindableControl; if (current == null || !current.RequiresControlState) { throw new Exception("The {controlState: ...} binding can only be used in a markup control that supports ControlState!"); // TODO: exception handling } else { object value; return current.ControlState.TryGetValue(Expression, out value) ? value : DefaultValue; } }
public override object Evaluate(DotvvmBindableControl control, DotvvmProperty property) { // I can execute the delegate, or find the property and get its value // TODO: whats better ?? return ExecDelegate(control, property != DotvvmBindableControl.DataContextProperty, setRootControl: true); //// find the parent markup control and calculate number of DataContext changes //int numberOfDataContextChanges; //var current = control.GetClosestControlBindingTarget(out numberOfDataContextChanges); //// get the property //var sourceProperty = DotvvmProperty.ResolveProperty(current.GetType(), OriginalString); //if (sourceProperty == null) //{ // throw new Exception(string.Format("The markup control of type '{0}' does not have a property '{1}'!", current.GetType(), ExpressionTree)); // TODO: exception handling //} //// check whether the property contains binding //if (current is DotvvmBindableControl) //{ // var originalBinding = ((DotvvmBindableControl)current).GetBinding(sourceProperty); // if (originalBinding != null && originalBinding.GetType() == typeof(ValueBindingExpression)) // { // // ValueBindingExpression must be modified to be evaluated against the original DataContext // return new ValueBindingExpression(string.Join(".", // Enumerable.Repeat("$parent", numberOfDataContextChanges) // .Concat(new[] { originalBinding.OriginalString }))); // } // else if (originalBinding != null) // { // return originalBinding; // } //} //// otherwise evaluate on server //return current.GetValue(sourceProperty); }
/// <summary> /// Evaluates the data context path and returns the visitor with hierarchy. /// </summary> private ExpressionEvaluationVisitor EvaluateDataContextPath(DotvvmBindableControl contextControl) { // get the hierarchy of DataContext the control is in var dataContexts = contextControl.GetAllAncestors().OfType<DotvvmBindableControl>() .Select(c => new { Binding = c.GetBinding(DotvvmBindableControl.DataContextProperty, false), Control = c }) .Where(b => b.Binding != null) .ToList(); // evaluate the DataContext path var viewRoot = contextControl.GetRoot(); var visitor = new ExpressionEvaluationVisitor(GetRootDataContext(viewRoot), viewRoot) { AllowMethods = AllowMethods }; for (var i = dataContexts.Count - 1; i >= 0; i--) { var binding = dataContexts[i].Binding; if (!(binding is ValueBindingExpression)) { throw new Exception("The DataContext property can only contain value bindings!"); // TODO: exception handling } var pathExpression = ((ValueBindingExpression)binding).GetViewModelPathExpression(dataContexts[i].Control, DotvvmBindableControl.DataContextProperty); EvaluateBinding(visitor, binding.Expression, pathExpression); } return visitor; }
private DotvvmControl GetRootControl(DotvvmBindableControl control) { return control.GetClosestControlBindingTarget(); }
protected void ExecUpdateDelegate(DotvvmBindableControl contextControl, object value, bool seeThis, bool setRootControl = false) { var dataContexts = GetDataContexts(contextControl, seeThis); var control = setRootControl ? GetRootControl(contextControl) : null; UpdateDelegate(dataContexts, control, value); }
public override object Evaluate(DotvvmBindableControl control, DotvvmProperty property) { throw new NotImplementedException(); }
/// <summary> /// Updates the viewModel with the new value. /// </summary> public virtual void UpdateSource(object value, DotvvmBindableControl control, DotvvmProperty property) { ExecUpdateDelegate(control, value, property != DotvvmBindableControl.DataContextProperty); }
/// <summary> /// Evaluates the binding. /// </summary> public virtual object Evaluate(DotvvmBindableControl control, DotvvmProperty property) { return ExecDelegate(control, property != DotvvmBindableControl.DataContextProperty); }
/// <summary> /// Updates the value. /// </summary> public override void UpdateSource(object value, DotvvmBindableControl control, DotvvmProperty property) { control.ControlState[property.Name] = value; }
/// <summary> /// Evaluates the PropertyInfo for the expression. /// </summary> public PropertyInfo EvaluateProperty(ValueBindingExpression expression, DotvvmProperty property, DotvvmBindableControl control, out object target) { var visitor = EvaluateDataContextPath(control); target = visitor.Result; // evaluate the final expression var node = ParseBinding(expression.Expression); string propertyName = null; if (node is IdentifierNameSyntax) { propertyName = ((IdentifierNameSyntax)node).ToString(); } else if (node is MemberAccessExpressionSyntax) { target = visitor.Visit(((MemberAccessExpressionSyntax)node).Expression); propertyName = ((MemberAccessExpressionSyntax)node).Name.ToString(); } if (propertyName != null && !visitor.IsSpecialPropertyName(propertyName)) { var propertyInfo = target.GetType().GetProperty(propertyName); if (propertyInfo != null) { return propertyInfo; } } throw new NotSupportedException(string.Format("Cannot update the source of the binding '{0}'!", expression.Expression)); }
public override object Evaluate(DotvvmBindableControl control, DotvvmProperty property) { return ExecDelegate(control, true, true); }
/// <summary> /// Finds the binding of the specified type on the specified viewmodel path. /// </summary> private FindBindingResult FindControlCommandBinding(string[] path, string commandId, DotvvmControl viewRootControl, DotvvmBindableControl targetControl, string validationTargetPath) { // walk the control tree and find the path ControlCommandBindingExpression resultBinding = null; DotvvmProperty resultProperty = null; DotvvmBindableControl resultControl = null; var walker = new ControlTreeWalker(viewRootControl); walker.ProcessControlTree((control) => { // compare path if (control is DotvvmBindableControl && ViewModelPathComparer.AreEqual(path, walker.CurrentPathArray)) { // find bindings of current control var bindableControl = (DotvvmBindableControl)control; var binding = bindableControl.GetAllBindings().Where(p => p.Value is ControlCommandBindingExpression) .FirstOrDefault(b => b.Value.BindingId == commandId); if (binding.Key != null) { // verify that the target control is the control command target if (bindableControl.GetClosestControlBindingTarget() == targetControl) { // we have found the binding, now get the validation path var currentValidationTargetPath = KnockoutHelper.GetValidationTargetExpression(bindableControl); if (currentValidationTargetPath == validationTargetPath) { // the validation path is equal, we have found the binding resultBinding = (ControlCommandBindingExpression)binding.Value; resultProperty = binding.Key; resultControl = bindableControl; } } } } }); return new FindBindingResult { Property = resultProperty, Binding = resultBinding, Control = resultControl }; }