/// <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 IAbstractBinding BuildBinding(BindingParserOptions bindingOptions, IDataContextStack dataContext, DothtmlBindingNode node, IPropertyDescriptor property) { return(new ResolvedBinding(bindingService, bindingOptions, (DataContextStack)dataContext, node.Value, property: property as DotvvmProperty) { DothtmlNode = node, }); }
protected override IDataContextStack CreateDataContextTypeStack(ITypeDescriptor viewModelType, ITypeDescriptor wrapperType = null, IDataContextStack parentDataContextStack = null) { var dataContextTypeStack = new DataContextStack(ResolvedTypeDescriptor.ToSystemType(viewModelType), parentDataContextStack as DataContextStack); if (wrapperType != null) { dataContextTypeStack.RootControlType = ResolvedTypeDescriptor.ToSystemType(wrapperType); } return dataContextTypeStack; }
private IAbstractControl ProcessHtmlComment(DothtmlNode node, IDataContextStack dataContext, DotHtmlCommentNode commentNode) { var text = commentNode.IsServerSide ? "" : "<!--" + commentNode.Value + "-->"; var literal = treeBuilder.BuildControl(rawLiteralMetadata.Value, node, dataContext); literal.ConstructorParameters = new object[] { text, commentNode.Value, true }; return(literal); }
public IAbstractBinding BuildBinding(BindingParserOptions bindingOptions, IDataContextStack dataContext, DothtmlBindingNode node, ITypeDescriptor resultType = null, Exception parsingError = null, object customData = null) { return(new ResolvedBinding() { BindingType = bindingOptions.BindingType, Value = node.Value, Expression = (Expression)customData, DataContextTypeStack = (DataContextStack)dataContext, ParsingError = parsingError, DothtmlNode = node, ResultType = resultType }); }
public IAbstractBinding BuildBinding(BindingParserOptions bindingOptions, DothtmlBindingNode node, IDataContextStack dataContext, Exception parsingError, ITypeDescriptor resultType, object customData) { return new ResolvedBinding() { BindingType = bindingOptions.BindingType, Value = node.Value, Expression = (Expression)customData, DataContextTypeStack = (DataContextStack)dataContext, ParsingError = parsingError, BindingNode = node, ResultType = resultType }; }
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; } }) })); }
private IAbstractControl ProcessBindingInText(DothtmlNode node, IDataContextStack dataContext) { var bindingNode = (DothtmlBindingNode)node; var literal = treeBuilder.BuildControl(literalMetadata.Value, node, dataContext); var textBinding = ProcessBinding(bindingNode, dataContext); var textProperty = treeBuilder.BuildPropertyBinding(Literal.TextProperty, textBinding, null); treeBuilder.SetProperty(literal, textProperty); var renderSpanElement = treeBuilder.BuildPropertyValue(Literal.RenderSpanElementProperty, false, null); treeBuilder.SetProperty(literal, renderSpanElement); return(literal); }
/// <summary> /// Processes the binding node. /// </summary> public IAbstractBinding ProcessBinding(DothtmlBindingNode node, IDataContextStack context, IPropertyDescriptor property) { var bindingOptions = controlResolver.ResolveBinding(node.Name); if (bindingOptions == null) { node.NameNode.AddError($"Binding {node.Name} could not be resolved."); bindingOptions = controlResolver.ResolveBinding("value"); // just try it as with value binding } if (context != null && context.NamespaceImports.Count > 0) { bindingOptions = bindingOptions.AddImports(context.NamespaceImports); } return(CompileBinding(node, bindingOptions, context, property)); }
/// <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)); } }
protected override IAbstractBinding CompileBinding(DothtmlBindingNode node, BindingParserOptions bindingOptions, IDataContextStack context) { Expression expression = null; Exception parsingError = null; ITypeDescriptor resultType = null; if (context == null) { parsingError = new DotvvmCompilationException("The DataContext couldn't be evaluated because of the errors above.", node.Tokens); } else { try { expression = bindingExpressionBuilder.Parse(node.Value, (DataContextStack)context, bindingOptions); resultType = new ResolvedTypeDescriptor(expression.Type); } catch (Exception exception) { parsingError = exception; } } return treeBuilder.BuildBinding(bindingOptions, node, context, parsingError, resultType, expression); }
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}'."); } }
/// <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())); }
/// <summary> /// Processes the parser node and builds a control. /// </summary> public IAbstractControl ProcessNode(IAbstractTreeNode parent, DothtmlNode node, IControlResolverMetadata parentMetadata, IDataContextStack dataContext) { try { if (node is DothtmlBindingNode) { // binding in text EnsureContentAllowed(parentMetadata, node); return(ProcessBindingInText(node, dataContext)); } else if (node is DotHtmlCommentNode) { // HTML comment var commentNode = node as DotHtmlCommentNode; return(ProcessHtmlComment(node, dataContext, commentNode)); } else if (node is DothtmlLiteralNode) { // text content var literalNode = (DothtmlLiteralNode)node; return(ProcessText(node, parentMetadata, dataContext, literalNode)); } else if (node is DothtmlElementNode) { // HTML element EnsureContentAllowed(parentMetadata, node); var element = (DothtmlElementNode)node; return(ProcessObjectElement(element, dataContext)); } else { throw new NotSupportedException($"The node of type '{node.GetType()}' is not supported!"); } } catch (DotvvmCompilationException ex) { if (ex.Tokens == null) { ex.Tokens = node.Tokens; ex.ColumnNumber = node.Tokens.First().ColumnNumber; ex.LineNumber = node.Tokens.First().LineNumber; } if (!LogError(ex, node)) { throw; } else { return(null); } } catch (Exception ex) { if (!LogError(ex, node)) { throw new DotvvmCompilationException("", ex, node.Tokens); } else { return(null); } } }
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); }
public override ITypeDescriptor GetChildDataContextType(ITypeDescriptor dataContext, IDataContextStack controlContextStack, IAbstractControl control, IPropertyDescriptor property = null) { return(TypeDescriptorUtils.GetCollectionItemType(dataContext)); }
public override IDataContextStack ChangeStackForChildren(IDataContextStack original, IAbstractControl control, IPropertyDescriptor property, Func <IDataContextStack, ITypeDescriptor, IDataContextStack> createNewFrame) { return(original.Parent); }
public abstract ITypeDescriptor GetChildDataContextType(ITypeDescriptor dataContext, IDataContextStack controlContextStack, IAbstractControl control, IPropertyDescriptor property = null);
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 HTML element that represents a new object. /// </summary> private IAbstractControl ProcessObjectElement(DothtmlElementNode element, IDataContextStack dataContext) { // build control var controlMetadata = controlResolver.ResolveControl(element.TagPrefix, element.TagName, out var constructorParameters); if (controlMetadata == null) { controlMetadata = controlResolver.ResolveControl("", element.TagName, out constructorParameters); constructorParameters = new[] { element.FullTagName }; element.AddError($"The control <{element.FullTagName}> could not be resolved! Make sure that the tagPrefix is registered in DotvvmConfiguration.Markup.Controls collection!"); } var control = treeBuilder.BuildControl(controlMetadata, element, dataContext); control.ConstructorParameters = constructorParameters; // resolve data context var dataContextAttribute = element.Attributes.FirstOrDefault(a => a.AttributeName == "DataContext"); if (dataContextAttribute != null) { ProcessAttribute(dataContextAttribute, control, dataContext); } IAbstractPropertySetter dataContextProperty; if (control.TryGetProperty(DotvvmBindableObject.DataContextProperty, out dataContextProperty) && dataContextProperty is IAbstractPropertyBinding) { var dataContextBinding = ((IAbstractPropertyBinding)dataContextProperty).Binding; if (dataContextBinding?.ResultType != null && dataContext != null) { dataContext = CreateDataContextTypeStack(dataContextBinding?.ResultType, parentDataContextStack: dataContext); } else if (dataContext != null) { dataContext = CreateDataContextTypeStack(null, dataContext); } else { dataContext = null; } control.DataContextTypeStack = dataContext; } if (controlMetadata.DataContextConstraint != null && dataContext != null && !controlMetadata.DataContextConstraint.IsAssignableFrom(dataContext.DataContextType)) { ((DothtmlNode)dataContextAttribute ?? element) .AddError($"The control '{controlMetadata.Type.Name}' requires a DataContext of type '{controlMetadata.DataContextConstraint.FullName}'!"); } // set properties from attributes foreach (var attribute in element.Attributes.Where(a => a.AttributeName != "DataContext")) { ProcessAttribute(attribute, control, dataContext); } // process control contents ProcessControlContent(control, element.Content); // check required properties IAbstractPropertySetter missingProperty; var missingProperties = control.Metadata.AllProperties.Where(p => p.MarkupOptions.Required && !control.TryGetProperty(p, out missingProperty)).ToList(); if (missingProperties.Any()) { element.AddError($"The control '{ control.Metadata.Type.FullName }' is missing required properties: { string.Join(", ", missingProperties.Select(p => "'" + p.Name + "'")) }."); } return(control); }
protected override IDataContextStack CreateDataContextTypeStack(ITypeDescriptor viewModelType, ITypeDescriptor wrapperType = null, IDataContextStack parentDataContextStack = null, IReadOnlyList <NamespaceImport> namespaceImports = null) { return(new DataContextStack( ResolvedTypeDescriptor.ToSystemType(viewModelType), parentDataContextStack as DataContextStack, ResolvedTypeDescriptor.ToSystemType(wrapperType), namespaceImports)); }
/// <summary> /// Creates the data context type stack object. /// </summary> protected abstract IDataContextStack CreateDataContextTypeStack(ITypeDescriptor viewModelType, IDataContextStack parentDataContextStack = null, IReadOnlyList <NamespaceImport> imports = null, IReadOnlyList <BindingExtensionParameter> extensionParameters = null);
/// <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!"); } }
protected override IAbstractBinding CompileBinding(DothtmlBindingNode node, BindingParserOptions bindingOptions, IDataContextStack context, IPropertyDescriptor property) { if (context == null) { node.AddError("The DataContext couldn't be evaluated because of the errors above."); } return(treeBuilder.BuildBinding(bindingOptions, context, node, property)); }
protected override IDataContextStack CreateDataContextTypeStack(ITypeDescriptor viewModelType, IDataContextStack parentDataContextStack = null, IReadOnlyList <NamespaceImport> namespaceImports = null, IReadOnlyList <BindingExtensionParameter> extensionParameters = null) { return(DataContextStack.Create( ResolvedTypeDescriptor.ToSystemType(viewModelType), parentDataContextStack as DataContextStack, namespaceImports, extensionParameters)); }
private IAbstractControl ProcessText(DothtmlNode node, IControlResolverMetadata parentMetadata, IDataContextStack dataContext, DothtmlLiteralNode literalNode) { var whitespace = string.IsNullOrWhiteSpace(literalNode.Value); if (!whitespace) { EnsureContentAllowed(parentMetadata, node); } string text; if (literalNode.Escape) { text = WebUtility.HtmlEncode(literalNode.Value); } else { text = literalNode.Value; } var literal = treeBuilder.BuildControl(rawLiteralMetadata.Value, node, dataContext); literal.ConstructorParameters = new object[] { text, literalNode.Value, whitespace }; return(literal); }
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 IAbstractControl BuildControl(IControlResolverMetadata metadata, DothtmlNode node, IDataContextStack dataContext) { return new ResolvedControl((ControlResolverMetadata)metadata, node, (DataContextStack)dataContext); }
public IAbstractTreeRoot BuildTreeRoot(IControlTreeResolver controlTreeResolver, IControlResolverMetadata metadata, DothtmlRootNode node, IDataContextStack dataContext, IReadOnlyDictionary <string, IReadOnlyList <IAbstractDirective> > directives) { return(new ResolvedTreeRoot((ControlResolverMetadata)metadata, node, (DataContextStack)dataContext, directives)); }
public IAbstractTreeRoot BuildTreeRoot(IControlTreeResolver controlTreeResolver, IControlResolverMetadata metadata, DothtmlRootNode node, IDataContextStack dataContext) { return new ResolvedTreeRoot((ControlResolverMetadata)metadata, node, (DataContextStack)dataContext); }
/// <summary> /// Processes the template contents. /// </summary> private List <IAbstractControl> ProcessTemplate(IAbstractTreeNode parent, IEnumerable <DothtmlNode> elementContent, IDataContextStack dataContext) { var content = elementContent.Select(e => ProcessNode(parent, e, placeholderMetadata.Value, dataContext)).Where(e => e != null); return(content.ToList()); }
public IAbstractControl BuildControl(IControlResolverMetadata metadata, DothtmlNode node, IDataContextStack dataContext) { return(new ResolvedControl((ControlResolverMetadata)metadata, node, (DataContextStack)dataContext)); }
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); }
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); } }
/// <summary> /// Compiles the binding. /// </summary> protected abstract IAbstractBinding CompileBinding(DothtmlBindingNode node, BindingParserOptions bindingOptions, IDataContextStack context, IPropertyDescriptor property);
public override ITypeDescriptor GetChildDataContextType(ITypeDescriptor dataContext, IDataContextStack controlContextStack, IAbstractControl control, IPropertyDescriptor property = null) { return new ResolvedTypeDescriptor(type); }
protected override IAbstractBinding CompileBinding(DothtmlBindingNode node, BindingParserOptions bindingOptions, IDataContextStack context) { Expression expression = null; Exception parsingError = null; ITypeDescriptor resultType = null; if (context == null) { parsingError = new DotvvmCompilationException("The DataContext couldn't be evaluated because of the errors above.", node.Tokens); } else { try { expression = bindingExpressionBuilder.Parse(node.Value, (DataContextStack)context, bindingOptions); resultType = new ResolvedTypeDescriptor(expression.Type); } catch (Exception exception) { parsingError = exception; } } return(treeBuilder.BuildBinding(bindingOptions, context, node, resultType, parsingError, expression)); }
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); }