public static object Create(string xaml, bool doNotThrow = false) { object inflatedView = null; using (var reader = XmlReader.Create(new StringReader(xaml))) { while (reader.Read()) { //Skip until element if (reader.NodeType == XmlNodeType.Whitespace) { continue; } if (reader.NodeType != XmlNodeType.Element) { Debug.WriteLine("Unhandled node {0} {1} {2}", reader.NodeType, reader.Name, reader.Value); continue; } var rootnode = new RuntimeRootNode(new XmlType(reader.NamespaceURI, reader.Name, null), null, (IXmlNamespaceResolver)reader); XamlParser.ParseXaml(rootnode, reader); var visitorContext = new HydratationContext { ExceptionHandler = doNotThrow ? e => { } : (Action <Exception>)null, }; var cvv = new CreateValuesVisitor(visitorContext); cvv.Visit((ElementNode)rootnode, null); inflatedView = rootnode.Root = visitorContext.Values [rootnode]; visitorContext.RootElement = inflatedView as BindableObject; Visit(rootnode, visitorContext); break; } } return(inflatedView); }
static void Visit(RootNode rootnode, HydratationContext visitorContext) { rootnode.Accept(new XamlNodeVisitor((node, parent) => node.Parent = parent), null); //set parents for {StaticResource} rootnode.Accept(new ExpandMarkupsVisitor(visitorContext), null); rootnode.Accept(new NamescopingVisitor(visitorContext), null); //set namescopes for {x:Reference} rootnode.Accept(new CreateValuesVisitor(visitorContext), null); rootnode.Accept(new RegisterXNamesVisitor(visitorContext), null); rootnode.Accept(new FillResourceDictionariesVisitor(visitorContext), null); rootnode.Accept(new ApplyPropertiesVisitor(visitorContext, true), null); }
void SetTemplate(ElementTemplate dt, INode node) { #pragma warning disable 0612 ((IDataTemplate)dt).LoadTemplate = () => { #pragma warning restore 0612 var context = new HydratationContext { ParentContext = Context, RootElement = Context.RootElement }; node.Accept(new ExpandMarkupsVisitor(context), null); node.Accept(new NamescopingVisitor(context), null); node.Accept(new CreateValuesVisitor(context), null); node.Accept(new RegisterXNamesVisitor(context), null); node.Accept(new FillResourceDictionariesVisitor(context), null); node.Accept(new ApplyPropertiesVisitor(context, true), null); return(context.Values[node]); }; }
void SetTemplate(ElementTemplate dt, INode node) { #pragma warning disable 0612 ((IDataTemplate)dt).LoadTemplate = () => { #pragma warning restore 0612 var cnode = node.Clone(); var context = new HydratationContext { ParentContext = Context, RootElement = Context.RootElement }; cnode.Accept(new XamlNodeVisitor((n, parent) => n.Parent = parent), node.Parent); //set parents for {StaticResource} cnode.Accept(new ExpandMarkupsVisitor(context), null); cnode.Accept(new NamescopingVisitor(context), null); cnode.Accept(new CreateValuesVisitor(context), null); cnode.Accept(new RegisterXNamesVisitor(context), null); cnode.Accept(new FillResourceDictionariesVisitor(context), null); cnode.Accept(new ApplyPropertiesVisitor(context, true), null); return(context.Values [cnode]); }; }
static object GetTargetProperty(object xamlelement, XmlName propertyName, HydratationContext context, IXmlLineInfo lineInfo) { var localName = propertyName.LocalName; //If it's an attached BP, update elementType and propertyName var bpOwnerType = xamlelement.GetType(); GetRealNameAndType(ref bpOwnerType, propertyName.NamespaceURI, ref localName, context, lineInfo); var property = GetBindableProperty(bpOwnerType, localName, lineInfo, false); if (property != null) { return(property); } var elementType = xamlelement.GetType(); var propertyInfo = elementType.GetRuntimeProperties().FirstOrDefault(p => p.Name == localName); return(propertyInfo); }
static bool GetRealNameAndType(ref Type elementType, string namespaceURI, ref string localname, HydratationContext context, IXmlLineInfo lineInfo) { var dotIdx = localname.IndexOf('.'); if (dotIdx > 0) { var typename = localname.Substring(0, dotIdx); localname = localname.Substring(dotIdx + 1); XamlParseException xpe; elementType = XamlParser.GetElementType(new XmlType(namespaceURI, typename, null), lineInfo, context.RootElement.GetType().GetTypeInfo().Assembly, out xpe); if (xpe != null) { throw xpe; } return(true); } return(false); }
public CreateValuesVisitor(HydratationContext context) { Context = context; }
public static void SetPropertyValue(object xamlelement, XmlName propertyName, object value, object rootElement, INode node, HydratationContext context, IXmlLineInfo lineInfo) { var localName = propertyName.LocalName; var serviceProvider = new XamlServiceProvider(node, context); Exception xpe = null; //If it's an attached BP, update elementType and propertyName var bpOwnerType = xamlelement.GetType(); var attached = GetRealNameAndType(ref bpOwnerType, propertyName.NamespaceURI, ref localName, context, lineInfo); var property = GetBindableProperty(bpOwnerType, localName, lineInfo, false); //If the target is an event, connect if (xpe == null && TryConnectEvent(xamlelement, localName, value, rootElement, lineInfo, out xpe)) { return; } //If Value is DynamicResource and it's a BP, SetDynamicResource if (xpe == null && TrySetDynamicResource(xamlelement, property, value, lineInfo, out xpe)) { return; } //If value is BindingBase, SetBinding if (xpe == null && TrySetBinding(xamlelement, property, localName, value, lineInfo, out xpe)) { return; } //If it's a BindableProberty, SetValue if (xpe == null && TrySetValue(xamlelement, property, attached, value, lineInfo, serviceProvider, out xpe)) { return; } //If we can assign that value to a normal property, let's do it if (xpe == null && TrySetProperty(xamlelement, localName, value, lineInfo, serviceProvider, out xpe)) { return; } //If it's an already initialized property, add to it if (xpe == null && TryAddToProperty(xamlelement, localName, value, lineInfo, serviceProvider, out xpe)) { return; } xpe = xpe ?? new XamlParseException($"Cannot assign property \"{localName}\": Property does not exists, or is not assignable, or mismatching type between value and property", lineInfo); if (context.DoNotThrowOnExceptions) { System.Diagnostics.Debug.WriteLine(xpe.Message); } else { throw xpe; } }
public ApplyPropertiesVisitor(HydratationContext context, bool stopOnResourceDictionary = false) { Context = context; StopOnResourceDictionary = stopOnResourceDictionary; }
public NamescopingVisitor(HydratationContext context) { Values = context.Values; }
public ExpandMarkupsVisitor(HydratationContext context) { Context = context; }
public FillResourceDictionariesVisitor(HydratationContext context) { Context = context; }
public RegisterXNamesVisitor(HydratationContext context) { Values = context.Values; }
static bool TrySetProperty(object element, string localName, object value, IXmlLineInfo lineInfo, XamlServiceProvider serviceProvider, HydratationContext context, out Exception exception) { exception = null; var elementType = element.GetType(); var propertyInfo = elementType.GetRuntimeProperties().FirstOrDefault(p => p.Name == localName); MethodInfo setter; if (propertyInfo == null || !propertyInfo.CanWrite || (setter = propertyInfo.SetMethod) == null) { return(false); } if (!IsVisibleFrom(setter, context.RootElement)) { return(false); } object convertedValue = value.ConvertTo(propertyInfo.PropertyType, () => propertyInfo, serviceProvider); if (convertedValue != null && !propertyInfo.PropertyType.IsInstanceOfType(convertedValue)) { return(false); } setter.Invoke(element, new object [] { convertedValue }); return(true); }
public static void SetPropertyValue(object xamlelement, XmlName propertyName, object value, object rootElement, INode node, HydratationContext context, IXmlLineInfo lineInfo) { var elementType = xamlelement.GetType(); var localname = propertyName.LocalName; var serviceProvider = new XamlServiceProvider(node, context); //If it's an attached BP, update elementType and propertyName var attached = GetRealNameAndType(ref elementType, propertyName.NamespaceURI, ref localname, context, lineInfo); //If the target is an event, connect var eventInfo = elementType.GetRuntimeEvent(localname); if (eventInfo != null && value is string) { var methodInfo = rootElement.GetType().GetRuntimeMethods().FirstOrDefault(mi => mi.Name == (string)value); if (methodInfo == null) { var xpe = new XamlParseException(string.Format("No method {0} found on type {1}", value, rootElement.GetType()), lineInfo); if (context.DoNotThrowOnExceptions) { System.Diagnostics.Debug.WriteLine(xpe.Message); return; } else { throw xpe; } } try { eventInfo.AddEventHandler(xamlelement, methodInfo.CreateDelegate(eventInfo.EventHandlerType, rootElement)); } catch (ArgumentException) { var xpe = new XamlParseException(string.Format("Method {0} does not have the correct signature", value), lineInfo); if (context.DoNotThrowOnExceptions) { System.Diagnostics.Debug.WriteLine(xpe.Message); } else { throw xpe; } } return; } var property = GetBindableProperty(elementType, localname, lineInfo, false); //If Value is DynamicResource and it's a BP, SetDynamicResource if (value is DynamicResource && property != null) { if (!(xamlelement.GetType()).GetTypeInfo().IsSubclassOf(typeof(BindableObject))) { throw new XamlParseException(string.Format("{0} is not a BindableObject", xamlelement.GetType().Name), lineInfo); } ((BindableObject)xamlelement).SetDynamicResource(property, ((DynamicResource)value).Key); return; } //If value is BindingBase, and target is a BindableProperty, SetBinding if (value is BindingBase && property != null) { if (!(xamlelement.GetType()).GetTypeInfo().IsSubclassOf(typeof(BindableObject))) { throw new XamlParseException(string.Format("{0} is not a BindableObject", xamlelement.GetType().Name), lineInfo); } ((BindableObject)xamlelement).SetBinding(property, value as BindingBase); return; } //If it's a BindableProberty, SetValue if (property != null) { if (!(xamlelement.GetType()).GetTypeInfo().IsSubclassOf(typeof(BindableObject))) { throw new XamlParseException(string.Format("{0} is not a BindableObject", xamlelement.GetType().Name), lineInfo); } Func <MemberInfo> minforetriever; if (attached) { minforetriever = () => elementType.GetRuntimeMethod("Get" + localname, new[] { typeof(BindableObject) }); } else { minforetriever = () => elementType.GetRuntimeProperty(localname); } var convertedValue = value.ConvertTo(property.ReturnType, minforetriever, serviceProvider); //SetValue doesn't throw on mismatching type, so check before to get a chance to try the property setting or the collection adding var nullable = property.ReturnTypeInfo.IsGenericType && property.ReturnTypeInfo.GetGenericTypeDefinition() == typeof(Nullable <>); if ((convertedValue == null && (!property.ReturnTypeInfo.IsValueType || nullable)) || (property.ReturnType.IsInstanceOfType(convertedValue))) { ((BindableObject)xamlelement).SetValue(property, convertedValue); return; } } var exception = new XamlParseException( String.Format("No Property of name {0} found", propertyName.LocalName), lineInfo); //If we can assign that value to a normal property, let's do it var propertyInfo = elementType.GetRuntimeProperties().FirstOrDefault(p => p.Name == localname); MethodInfo setter; if (propertyInfo != null && propertyInfo.CanWrite && (setter = propertyInfo.SetMethod) != null) { object convertedValue = value.ConvertTo(propertyInfo.PropertyType, () => propertyInfo, serviceProvider); if (convertedValue == null || propertyInfo.PropertyType.IsInstanceOfType(convertedValue)) { try { setter.Invoke(xamlelement, new[] { convertedValue }); return; } catch (ArgumentException) { } } else { exception = new XamlParseException( String.Format("Cannot assign property \"{0}\": type mismatch between \"{1}\" and \"{2}\"", propertyName.LocalName, value.GetType(), propertyInfo.PropertyType), lineInfo); } } //If it's an already initialized property, add to it MethodInfo getter; if (propertyInfo != null && propertyInfo.CanRead && (getter = propertyInfo.GetMethod) != null) { IEnumerable collection; MethodInfo addMethod; if ((collection = getter.Invoke(xamlelement, new object[] { }) as IEnumerable) != null && (addMethod = collection.GetType().GetRuntimeMethods().First(mi => mi.Name == "Add" && mi.GetParameters().Length == 1)) != null) { addMethod.Invoke(collection, new[] { value.ConvertTo(addMethod.GetParameters()[0].ParameterType, (Func <TypeConverter>)null, serviceProvider) }); return; } } if (context.DoNotThrowOnExceptions) { System.Diagnostics.Debug.WriteLine(exception.Message); } else { throw exception; } }