public static IAbstractPropertySetter GetPropertyGroupMember(this IAbstractControl control, string prefix, string memberName) { IAbstractPropertySetter value; control.TryGetProperty(control.Metadata.GetPropertyGroupMember(prefix, memberName), out value); return(value); }
/// <summary> /// Resolves the content of the control immediately during the parsing. /// Override this method if you need lazy loading of tree node contents. /// </summary> protected virtual void ResolveControlContentImmediately(IAbstractControl control, List <DothtmlNode> content) { foreach (var node in content) { var child = ProcessNode(control, node, control.Metadata, control.DataContextTypeStack); if (child != null) { treeBuilder.AddChildControl(control, child); } } }
public IEnumerable <ControlUsageError> Validate(IAbstractControl control) { var type = GetControlType(control.Metadata); if (type == null) { return(null); } var result = new List <ControlUsageError>(); var methods = cache.GetOrAdd(type, FindMethods); foreach (var method in methods) { var par = method.GetParameters(); var args = new object[par.Length]; for (int i = 0; i < par.Length; i++) { if (par[i].ParameterType.IsAssignableFrom(control.GetType())) { args[i] = control; } else if (control.DothtmlNode != null && par[i].ParameterType.IsAssignableFrom(control.DothtmlNode.GetType())) { args[i] = control.DothtmlNode; } else { goto Error; // I think it is better that throw exceptions and catch them } } var r = method.Invoke(null, args); if (r is IEnumerable <ControlUsageError> ) { result.AddRange((IEnumerable <ControlUsageError>)r); } else if (r is IEnumerable <string> ) { result.AddRange((r as IEnumerable <string>).Select(e => new ControlUsageError(e))); } continue; Error :; } return(result // add current node to the error, if no control is specified .Select(e => e.Nodes.Length == 0 ? new ControlUsageError(e.ErrorMessage, control.DothtmlNode) : e)); }
public IEnumerable<ControlUsageError> Validate(IAbstractControl control) { var type = GetControlType(control.Metadata); if (type == null) return null; var result = new List<ControlUsageError>(); var methods = cache.GetOrAdd(type, FindMethods); foreach (var method in methods) { var par = method.GetParameters(); var args = new object[par.Length]; for (int i = 0; i < par.Length; i++) { if (par[i].ParameterType.IsAssignableFrom(control.GetType())) { args[i] = control; } else if (control.DothtmlNode != null && par[i].ParameterType.IsAssignableFrom(control.DothtmlNode.GetType())) { args[i] = control.DothtmlNode; } else { goto Error; // I think it is better that throw exceptions and catch them } } var r = method.Invoke(null, args); if(r is IEnumerable<ControlUsageError>) { result.AddRange((IEnumerable<ControlUsageError>)r); } else if(r is IEnumerable<string>) { result.AddRange((r as IEnumerable<string>).Select(e => new ControlUsageError(e, new[] { control.DothtmlNode }))); } continue; Error:; } return result; }
private void ProcessAttributeProperties(IAbstractControl control, DothtmlAttributeNode[] nodes, IDataContextStack dataContext) { var doneAttributes = new HashSet <DothtmlAttributeNode>(); string getName(DothtmlAttributeNode n) => n.AttributePrefix == null ? n.AttributeName : n.AttributePrefix + ":" + n.AttributeName; void resolveAttribute(DothtmlAttributeNode attribute) { var name = getName(attribute); if (!doneAttributes.Add(attribute)) { return; } var property = controlResolver.FindProperty(control.Metadata, name); if (property == null) { attribute.AddError($"The control '{control.Metadata.Type}' does not have a property '{attribute.AttributeName}' and does not allow HTML attributes!"); } else { var dependsOn = property.DataContextChangeAttributes.SelectMany(c => c.PropertyDependsOn); foreach (var p in dependsOn.SelectMany(t => nodes.Where(n => t == getName(n)))) { resolveAttribute(p); } ProcessAttribute(property, attribute, control, dataContext); } } // set properties from attributes foreach (var attr in nodes) { resolveAttribute(attr); } }
public override ITypeDescriptor GetChildDataContextType(ITypeDescriptor dataContext, IDataContextStack controlContextStack, IAbstractControl control, IPropertyDescriptor property = null) { IPropertyDescriptor controlProperty; if (!control.Metadata.TryGetProperty(PropertyName, out controlProperty)) { throw new Exception($"The property '{PropertyName}' was not found on control '{control.Metadata.Type}'!"); } IAbstractPropertySetter setter; if (control.TryGetProperty(controlProperty, out setter)) { var binding = setter as IAbstractPropertyBinding; if (binding == null) { return dataContext; } return binding.Binding.ResultType; } else { if (AllowMissingProperty) return dataContext; else throw new Exception($"Property '{PropertyName}' is required on '{control.Metadata.Type.Name}'."); } }
public void SetProperty(IAbstractControl control, IAbstractPropertySetter setter) { ((ResolvedControl)control).SetProperty((ResolvedPropertySetter)setter); }
public override ITypeDescriptor GetChildDataContextType(ITypeDescriptor dataContext, IDataContextStack controlContextStack, IAbstractControl control, IPropertyDescriptor property = null) { return(new ResolvedTypeDescriptor(type)); }
public void AddChildControl(IAbstractContentNode control, IAbstractControl child) { ((ResolvedContentNode)control).AddChild((ResolvedControl)child); }
public abstract ITypeDescriptor GetChildDataContextType(ITypeDescriptor dataContext, IDataContextStack controlContextStack, IAbstractControl control, IPropertyDescriptor property = null);
public static bool HasPropertyValue(this IAbstractControl control, IPropertyDescriptor property) { IAbstractPropertySetter setter; return(control.TryGetProperty(property, out setter) && setter is IAbstractPropertyValue); }
/// <summary> /// Gets the data context change behavior for the specified control property. /// </summary> protected virtual IDataContextStack GetDataContextChange(IDataContextStack dataContext, IAbstractControl control, IPropertyDescriptor property) { if (dataContext == null) { return(null); } var manipulationAttribute = property != null ? property.DataContextManipulationAttribute : control.Metadata.DataContextManipulationAttribute; if (manipulationAttribute != null) { return(manipulationAttribute.ChangeStackForChildren(dataContext, control, property, (parent, changeType) => CreateDataContextTypeStack(changeType, parentDataContextStack: parent))); } var attributes = property != null ? property.DataContextChangeAttributes : control.Metadata.DataContextChangeAttributes; if (attributes == null || attributes.Length == 0) { return(dataContext); } var type = dataContext.DataContextType; foreach (var attribute in attributes.OrderBy(a => a.Order)) { type = attribute.GetChildDataContextType(type, dataContext, control, property); if (type == null) { break; } } return(CreateDataContextTypeStack(type, parentDataContextStack: dataContext)); }
public override ITypeDescriptor?GetChildDataContextType(ITypeDescriptor dataContext, IDataContextStack controlContextStack, IAbstractControl control, IPropertyDescriptor?property = null) { return(new ResolvedTypeDescriptor(GenericTypeDefinition).MakeGenericType(dataContext)); }
public void SetHtmlAttribute(IAbstractControl control, string attributeName, object value) { ((ResolvedControl) control).SetHtmlAttribute(attributeName, value); }
public IAbstractPropertyControl BuildPropertyControl(IPropertyDescriptor property, IAbstractControl control) { return new ResolvedPropertyControl((DotvvmProperty)property, (ResolvedControl)control); }
public abstract IDataContextStack ChangeStackForChildren(IDataContextStack original, IAbstractControl control, IPropertyDescriptor property, Func<IDataContextStack, ITypeDescriptor, IDataContextStack> createNewFrame);
/// <summary> /// Processes the attribute node. /// </summary> private void ProcessAttribute(DothtmlAttributeNode attribute, IAbstractControl control, IDataContextStack dataContext) { if (attribute.AttributePrefix == "html") { if (!control.Metadata.HasHtmlAttributesCollection) { attribute.AddError($"The control '{control.Metadata.Type.FullName}' cannot use HTML attributes!"); } else { try { treeBuilder.SetHtmlAttribute(control, ProcessAttributeValue(attribute, dataContext)); } catch (NotSupportedException ex) { if (ex.InnerException == null) { throw; } else { attribute.AddError(ex.Message); } } } return; } if (!string.IsNullOrEmpty(attribute.AttributePrefix)) { attribute.AddError("Attributes with XML namespaces are not supported!"); return; } // find the property var property = FindProperty(control.Metadata, attribute.AttributeName); if (property != null) { if (control.HasProperty(property)) { attribute.AttributeNameNode.AddError($"control '{ ((DothtmlElementNode)control.DothtmlNode).FullTagName }' already has property '{ attribute.AttributeName }'."); } if (property.IsBindingProperty || property.DataContextManipulationAttribute != null) // when DataContextManipulationAttribute is set, lets hope that author knows what is he doing. { dataContext = GetDataContextChange(dataContext, control, property); } if (!property.MarkupOptions.MappingMode.HasFlag(MappingMode.Attribute)) { attribute.AddError($"The property '{property.FullName}' cannot be used as a control attribute!"); return; } // set the property if (attribute.ValueNode == null) { attribute.AddError($"The attribute '{property.Name}' on the control '{control.Metadata.Type.FullName}' must have a value!"); } else if (attribute.ValueNode is DothtmlValueBindingNode) { // binding var bindingNode = (attribute.ValueNode as DothtmlValueBindingNode).BindingNode; if (property.IsVirtual) { attribute.ValueNode.AddError($"The property '{ property.FullName }' cannot contain bindings because it's not DotvvmProperty."); } else if (treatBindingAsHardCodedValue.Contains(bindingNode.Name)) { if (!property.MarkupOptions.AllowHardCodedValue) { attribute.ValueNode.AddError($"The property '{ property.FullName }' cannot contain {bindingNode.Name} binding, it can contain only hard-coded value or resource binding."); } } else { if (!property.MarkupOptions.AllowBinding) { attribute.ValueNode.AddError($"The property '{ property.FullName }' cannot contain {bindingNode.Name} binding."); } } var binding = ProcessBinding(bindingNode, dataContext); var bindingProperty = treeBuilder.BuildPropertyBinding(property, binding, attribute); treeBuilder.SetProperty(control, bindingProperty); } else { // hard-coded value in markup if (!property.MarkupOptions.AllowHardCodedValue) { attribute.ValueNode.AddError($"The property '{ property.FullName }' cannot contain hard coded value."); } var textValue = attribute.ValueNode as DothtmlValueTextNode; var value = ConvertValue(textValue.Text, property.PropertyType); var propertyValue = treeBuilder.BuildPropertyValue(property, value, attribute); treeBuilder.SetProperty(control, propertyValue); } } else if (control.Metadata.HasHtmlAttributesCollection) { // if the property is not found, add it as an HTML attribute try { treeBuilder.SetHtmlAttribute(control, ProcessAttributeValue(attribute, dataContext)); } catch (NotSupportedException ex) { if (ex.InnerException == null) { throw; } else { attribute.AddError(ex.Message); } } } else { attribute.AddError($"The control '{control.Metadata.Type}' does not have a property '{attribute.AttributeName}' and does not allow HTML attributes!"); } }
/// <summary> /// Gets the data context change behavior for the specified control property. /// </summary> protected virtual IDataContextStack GetDataContextChange(IDataContextStack dataContext, IAbstractControl control, IPropertyDescriptor property) { if (dataContext == null) { return(null); } var manipulationAttribute = property != null ? property.DataContextManipulationAttribute : control.Metadata.DataContextManipulationAttribute; if (manipulationAttribute != null) { return(manipulationAttribute.ChangeStackForChildren(dataContext, control, property, (parent, changeType) => CreateDataContextTypeStack(changeType, parentDataContextStack: parent))); } var attributes = property != null ? property.DataContextChangeAttributes : control.Metadata.DataContextChangeAttributes; if (attributes == null || attributes.Length == 0) { return(dataContext); } try { var(type, extensionParameters) = ApplyContextChange(dataContext, attributes, control, property); if (type == null) { return(dataContext); } else { return(CreateDataContextTypeStack(type, parentDataContextStack: dataContext, extensionParameters: extensionParameters.ToArray())); } } catch (Exception exception) { var node = property != null && control.TryGetProperty(property, out var v) ? v.DothtmlNode : control.DothtmlNode; node?.AddError($"Could not compute the type of DataContext: {exception}"); return(CreateDataContextTypeStack(null, parentDataContextStack: dataContext)); } }
/// <summary> /// Processes the element which contains property value. /// </summary> private IAbstractPropertySetter ProcessElementProperty(IAbstractControl control, IPropertyDescriptor property, IEnumerable <DothtmlNode> elementContent, DothtmlElementNode propertyWrapperElement) { IEnumerable <IAbstractControl> filterByType(ITypeDescriptor type, IEnumerable <IAbstractControl> controls) => FilterOrError(controls, c => c.Metadata.Type.IsAssignableTo(type), c => { // empty nodes are only filtered, non-empty nodes cause errors if (c.DothtmlNode.IsNotEmpty()) { c.DothtmlNode.AddError($"Control type {c.Metadata.Type.FullName} can't be used in collection of type {type.FullName}."); } }); // resolve data context var dataContext = control.DataContextTypeStack; dataContext = GetDataContextChange(dataContext, control, property); // the element is a property if (IsTemplateProperty(property)) { // template return(treeBuilder.BuildPropertyTemplate(property, ProcessTemplate(control, elementContent, dataContext), propertyWrapperElement)); } else if (IsCollectionProperty(property)) { var collectionType = GetCollectionType(property); // collection of elements var collection = elementContent.Select(childObject => ProcessNode(control, childObject, control.Metadata, dataContext)); if (collectionType != null) { collection = filterByType(collectionType, collection); } return(treeBuilder.BuildPropertyControlCollection(property, collection.ToArray(), propertyWrapperElement)); } else if (property.PropertyType.IsEqualTo(new ResolvedTypeDescriptor(typeof(string)))) { // string property var strings = FilterNodes <DothtmlLiteralNode>(elementContent, property); var value = string.Concat(strings.Select(s => s.Value)); return(treeBuilder.BuildPropertyValue(property, value, propertyWrapperElement)); } else if (IsControlProperty(property)) { var children = filterByType(property.PropertyType, elementContent.Select(childObject => ProcessNode(control, childObject, control.Metadata, dataContext))).ToArray(); if (children.Length > 1) { // try with the empty nodes are excluded children = children.Where(c => c.DothtmlNode.IsNotEmpty()).ToArray(); if (children.Length > 1) { foreach (var c in children.Skip(1)) { c.DothtmlNode.AddError($"The property '{property.MarkupOptions.Name}' can have only one child element!"); } } } if (children.Length >= 1) { return(treeBuilder.BuildPropertyControl(property, children[0], propertyWrapperElement)); } else { return(treeBuilder.BuildPropertyControl(property, null, propertyWrapperElement)); } } else { control.DothtmlNode.AddError($"The property '{property.FullName}' is not supported!"); return(treeBuilder.BuildPropertyValue(property, null, propertyWrapperElement)); } }
public abstract IDataContextStack ChangeStackForChildren(IDataContextStack original, IAbstractControl control, IPropertyDescriptor property, Func <IDataContextStack, ITypeDescriptor, IDataContextStack> createNewFrame);
public override ITypeDescriptor GetChildDataContextType(ITypeDescriptor dataContext, IDataContextStack controlContextStack, IAbstractControl control, IPropertyDescriptor property = null) { return new ResolvedTypeDescriptor(type); }
public override IDataContextStack ChangeStackForChildren(IDataContextStack original, IAbstractControl control, IPropertyDescriptor property, Func <IDataContextStack, ITypeDescriptor, IDataContextStack> createNewFrame) { return(original.Parent); }
public override IDataContextStack ChangeStackForChildren(IDataContextStack original, IAbstractControl control, IPropertyDescriptor property, Func <IDataContextStack, ITypeDescriptor, IDataContextStack> createNewFrame) { return(DataContextStack.Create(ResolvedTypeDescriptor.ToSystemType(original.DataContextType), (DataContextStack)original.Parent, bindingPropertyResolvers: new Delegate[] { new Func <ParsedExpressionBindingProperty, ParsedExpressionBindingProperty>(e => { if (e.Expression.NodeType == ExpressionType.Constant && (string)((ConstantExpression)e.Expression).Value == "abc") { return new ParsedExpressionBindingProperty(Expression.Constant("def")); } else { return e; } }) })); }
public override ITypeDescriptor GetChildDataContextType(ITypeDescriptor dataContext, IDataContextStack controlContextStack, IAbstractControl control, IPropertyDescriptor property = null) { if (!control.Metadata.TryGetProperty(PropertyName, out var controlProperty)) { throw new Exception($"The property '{PropertyName}' was not found on control '{control.Metadata.Type}'!"); } if (control.TryGetProperty(controlProperty, out var setter) && setter is IAbstractPropertyBinding binding) { return(binding.Binding.ResultType); } return(controlProperty.PropertyType); }
=> control.Content.All(c => !DothtmlNodeHelper.IsNotEmpty(c.DothtmlNode)); // allow only whitespace literals public static bool HasProperty(this IAbstractControl control, IPropertyDescriptor property) { IAbstractPropertySetter blackHole; return(control.TryGetProperty(property, out blackHole)); }
/// <summary> /// Processes the content of the control node. /// </summary> public void ProcessControlContent(IAbstractControl control, IEnumerable <DothtmlNode> nodes) { var content = new List <DothtmlNode>(); bool properties = true; foreach (var node in nodes) { var element = node as DothtmlElementNode; if (element != null && properties) { var property = controlResolver.FindProperty(control.Metadata, element.TagName); if (property != null && string.IsNullOrEmpty(element.TagPrefix) && property.MarkupOptions.MappingMode.HasFlag(MappingMode.InnerElement)) { content.Clear(); string error; if (!treeBuilder.AddProperty(control, ProcessElementProperty(control, property, element.Content, element), out error)) { element.AddError(error); } foreach (var attr in element.Attributes) { attr.AddError("Attributes can't be set on element property."); } } else { content.Add(node); if (node.IsNotEmpty()) { properties = false; } } } else { content.Add(node); } } if (control.Metadata.DefaultContentProperty != null) { if (control.HasProperty(control.Metadata.DefaultContentProperty)) { foreach (var c in content) { if (c.IsNotEmpty()) { c.AddError($"Property { control.Metadata.DefaultContentProperty.FullName } was already set."); } } } else if (!content.All(c => c is DothtmlLiteralNode && string.IsNullOrWhiteSpace(((DothtmlLiteralNode)c).Value))) { string error; if (!treeBuilder.AddProperty(control, ProcessElementProperty(control, control.Metadata.DefaultContentProperty, content, null), out error)) { content.First().AddError(error); } } } else { if (!control.Metadata.IsContentAllowed) { foreach (var item in content) { if (item.IsNotEmpty()) { item.AddError($"Content not allowed inside {control.Metadata.Type.Name}."); } } } else { ResolveControlContentImmediately(control, content); } } }
public static IAbstractPropertySetter GetHtmlAttribute(this IAbstractControl control, string memberName) => GetPropertyGroupMember(control, "", memberName);
/// <summary> /// Gets the data context change behavior for the specified control property. /// </summary> protected virtual IDataContextStack GetDataContextChange(IDataContextStack dataContext, IAbstractControl control, IPropertyDescriptor property) { if (dataContext == null) { return(null); } var manipulationAttribute = property != null ? property.DataContextManipulationAttribute : control.Metadata.DataContextManipulationAttribute; if (manipulationAttribute != null) { return(manipulationAttribute.ChangeStackForChildren(dataContext, control, property, (parent, changeType) => CreateDataContextTypeStack(changeType, parentDataContextStack: parent))); } var attributes = property != null ? property.DataContextChangeAttributes : control.Metadata.DataContextChangeAttributes; if (attributes == null || attributes.Length == 0) { return(dataContext); } var(type, extensionParameters) = ApplyContextChange(dataContext, attributes, control, property); return(CreateDataContextTypeStack(type, parentDataContextStack: dataContext, extensionParameters: extensionParameters.ToArray())); }
public static bool HasEmptyContent(this IAbstractControl control) => control.Content.All(c => !DothtmlNodeHelper.IsNotEmpty(c.DothtmlNode)); // allow only whitespace literals
public override ITypeDescriptor GetChildDataContextType(ITypeDescriptor dataContext, IDataContextStack controlContextStack, IAbstractControl control, IPropertyDescriptor property = null) { return(TypeDescriptorUtils.GetCollectionItemType(dataContext)); }
public override ITypeDescriptor GetChildDataContextType(ITypeDescriptor dataContext, IDataContextStack controlContextStack, IAbstractControl control, IPropertyDescriptor property = null) { if (!control.Metadata.TryGetProperty(PropertyName, out var controlProperty)) { throw new Exception($"The property '{PropertyName}' was not found on control '{control.Metadata.Type}'!"); } if (control.TryGetProperty(controlProperty, out var setter)) { return(setter is IAbstractPropertyBinding binding ? binding.Binding.ResultType : dataContext); } if (AllowMissingProperty) { return(dataContext); } throw new Exception($"Property '{PropertyName}' is required on '{control.Metadata.Type.Name}'."); }
/// <summary> /// Processes the attribute node. /// </summary> private void ProcessAttribute(DothtmlAttributeNode attribute, IAbstractControl control, IDataContextStack dataContext) { var name = attribute.AttributePrefix == null ? attribute.AttributeName : attribute.AttributePrefix + ":" + attribute.AttributeName; // find the property var property = controlResolver.FindProperty(control.Metadata, name); if (property != null) { if (property.IsBindingProperty || property.DataContextManipulationAttribute != null) // when DataContextManipulationAttribute is set, lets hope that author knows what is he doing. { dataContext = GetDataContextChange(dataContext, control, property); } if (!property.MarkupOptions.MappingMode.HasFlag(MappingMode.Attribute)) { attribute.AddError($"The property '{property.FullName}' cannot be used as a control attribute!"); return; } // set the property if (attribute.ValueNode == null) { // implicitly set boolean property if (property.PropertyType.IsEqualTo(new ResolvedTypeDescriptor(typeof(bool)))) { string error; if (!treeBuilder.AddProperty(control, treeBuilder.BuildPropertyValue(property, true, attribute), out error)) { attribute.AddError(error); } } else if (property.MarkupOptions.AllowAttributeWithoutValue) { string error; if (!treeBuilder.AddProperty(control, treeBuilder.BuildPropertyValue(property, (property as DotVVM.Framework.Binding.DotvvmProperty)?.DefaultValue, attribute), out error)) { attribute.AddError(error); } } else { attribute.AddError($"The attribute '{property.Name}' on the control '{control.Metadata.Type.FullName}' must have a value!"); } } else if (attribute.ValueNode is DothtmlValueBindingNode) { // binding var bindingNode = (attribute.ValueNode as DothtmlValueBindingNode).BindingNode; if (property.IsVirtual && !property.IsBindingProperty && property.PropertyType.FullName != "System.Object") { attribute.ValueNode.AddError($"The property '{ property.FullName }' cannot contain bindings because it's not DotvvmProperty."); } else if (!treatBindingAsHardCodedValue.Contains(bindingNode.Name)) { if (!property.MarkupOptions.AllowBinding) { attribute.ValueNode.AddError($"The property '{ property.FullName }' cannot contain {bindingNode.Name} binding."); } } var binding = ProcessBinding(bindingNode, dataContext, property); var bindingProperty = treeBuilder.BuildPropertyBinding(property, binding, attribute); string error; if (!treeBuilder.AddProperty(control, bindingProperty, out error)) { attribute.AddError(error); } } else { // hard-coded value in markup if (!property.MarkupOptions.AllowHardCodedValue) { attribute.ValueNode.AddError($"The property '{ property.FullName }' cannot contain hard coded value."); } var textValue = attribute.ValueNode as DothtmlValueTextNode; var value = ConvertValue(WebUtility.HtmlDecode(textValue.Text), property.PropertyType); var propertyValue = treeBuilder.BuildPropertyValue(property, value, attribute); string error; if (!treeBuilder.AddProperty(control, propertyValue, out error)) { attribute.AddError(error); } } } else { attribute.AddError($"The control '{control.Metadata.Type}' does not have a property '{attribute.AttributeName}' and does not allow HTML attributes!"); } }
public bool AddProperty(IAbstractControl control, IAbstractPropertySetter setter, out string error) { return(((ResolvedControl)control).SetProperty((ResolvedPropertySetter)setter, false, out error)); }
/// <summary> /// Processes the element which contains property value. /// </summary> private IAbstractPropertySetter ProcessElementProperty(IAbstractControl control, IPropertyDescriptor property, IEnumerable <DothtmlNode> elementContent, DothtmlElementNode propertyWrapperElement) { // resolve data context var dataContext = control.DataContextTypeStack; dataContext = GetDataContextChange(dataContext, control, property); // the element is a property if (IsTemplateProperty(property)) { // template return(treeBuilder.BuildPropertyTemplate(property, ProcessTemplate(control, elementContent, dataContext), propertyWrapperElement)); } else if (IsCollectionProperty(property)) { var collectionType = GetCollectionType(property); // collection of elements var collection = FilterNodes <DothtmlElementNode>(elementContent, property) .Select(childObject => ProcessObjectElement(childObject, dataContext)); if (collectionType != null) { collection = FilterOrError(collection, c => c.Metadata.Type.IsAssignableTo(collectionType), c => c.DothtmlNode.AddError($"Control type {c.Metadata.Type.FullName} can't be used in collection of type {collectionType.FullName}.")); } return(treeBuilder.BuildPropertyControlCollection(property, collection.ToArray(), propertyWrapperElement)); } else if (property.PropertyType.IsEqualTo(new ResolvedTypeDescriptor(typeof(string)))) { // string property var strings = FilterNodes <DothtmlLiteralNode>(elementContent, property); var value = string.Concat(strings.Select(s => s.Value)); return(treeBuilder.BuildPropertyValue(property, value, propertyWrapperElement)); } else if (IsControlProperty(property)) { // new object var children = FilterNodes <DothtmlElementNode>(elementContent, property).ToList(); if (children.Count > 1) { foreach (var c in children.Skip(1)) { c.AddError($"The property '{property.MarkupOptions.Name}' can have only one child element!"); } children = children.Take(1).ToList(); } if (children.Count == 1) { return(treeBuilder.BuildPropertyControl(property, ProcessObjectElement(children[0], dataContext), propertyWrapperElement)); } else { return(treeBuilder.BuildPropertyControl(property, null, propertyWrapperElement)); } } else { control.DothtmlNode.AddError($"The property '{property.FullName}' is not supported!"); return(treeBuilder.BuildPropertyValue(property, null, propertyWrapperElement)); } }
public static (ITypeDescriptor type, List <BindingExtensionParameter> extensionParameters) ApplyContextChange(IDataContextStack dataContext, DataContextChangeAttribute[] attributes, IAbstractControl control, IPropertyDescriptor property) { var type = dataContext.DataContextType; var extensionParameters = new List <BindingExtensionParameter>(); foreach (var attribute in attributes.OrderBy(a => a.Order)) { if (type == null) { break; } extensionParameters.AddRange(attribute.GetExtensionParameters(type)); type = attribute.GetChildDataContextType(type, dataContext, control, property); } return(type, extensionParameters); }
public IAbstractPropertyControl BuildPropertyControl(IPropertyDescriptor property, IAbstractControl control, DothtmlElementNode wrapperElement) { return(new ResolvedPropertyControl((DotvvmProperty)property, (ResolvedControl)control) { DothtmlNode = wrapperElement }); }
public override IDataContextStack ChangeStackForChildren(IDataContextStack original, IAbstractControl control, IPropertyDescriptor property, Func<IDataContextStack, ITypeDescriptor, IDataContextStack> createNewFrame) { return original.Parent; }
public override ITypeDescriptor GetChildDataContextType(ITypeDescriptor dataContext, IDataContextStack controlContextStack, IAbstractControl control, IPropertyDescriptor property = null) { return TypeDescriptorUtils.GetCollectionItemType(dataContext); }