public static object Create(string xaml, bool doNotThrow, bool useDesignProperties) { doNotThrow = doNotThrow || ResourceLoader.ExceptionHandler2 != null; void ehandler(Exception e) => ResourceLoader.ExceptionHandler2?.Invoke((e, null)); object inflatedView = null; using (var textreader = new StringReader(xaml)) using (var reader = XmlReader.Create(textreader)) { while (reader.Read()) { //Skip until element if (reader.NodeType == XmlNodeType.Whitespace) { continue; } if (reader.NodeType == XmlNodeType.XmlDeclaration) { continue; } if (reader.NodeType != XmlNodeType.Element) { Debug.WriteLine("Unhandled node {0} {1} {2}", reader.NodeType, reader.Name, reader.Value); continue; } var typeArguments = XamlParser.GetTypeArguments(reader); var rootnode = new RuntimeRootNode(new XmlType(reader.NamespaceURI, reader.Name, typeArguments), null, (IXmlNamespaceResolver)reader) { LineNumber = ((IXmlLineInfo)reader).LineNumber, LinePosition = ((IXmlLineInfo)reader).LinePosition }; XamlParser.ParseXaml(rootnode, reader); var visitorContext = new HydrationContext { ExceptionHandler = doNotThrow ? ehandler : (Action <Exception>)null, }; var cvv = new CreateValuesVisitor(visitorContext); cvv.Visit((ElementNode)rootnode, null); inflatedView = rootnode.Root = visitorContext.Values[rootnode]; if (XamlFilePathAttribute.GetFilePathForObject(inflatedView) is string path) { VisualDiagnostics.RegisterSourceInfo(inflatedView, new Uri($"{path};assembly={inflatedView.GetType().GetTypeInfo().Assembly.GetName().Name}", UriKind.Relative), ((IXmlLineInfo)rootnode).LineNumber, ((IXmlLineInfo)rootnode).LinePosition); VisualDiagnostics.SendVisualTreeChanged(null, inflatedView); } visitorContext.RootElement = inflatedView as BindableObject; Visit(rootnode, visitorContext, useDesignProperties); break; } } return(inflatedView); }
public static void Load(object view, string xaml, Assembly rootAssembly, bool useDesignProperties) { using (var textReader = new StringReader(xaml)) using (var reader = XmlReader.Create(textReader)) { while (reader.Read()) { //Skip until element if (reader.NodeType == XmlNodeType.Whitespace) { continue; } if (reader.NodeType == XmlNodeType.XmlDeclaration) { 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), view, (IXmlNamespaceResolver)reader) { LineNumber = ((IXmlLineInfo)reader).LineNumber, LinePosition = ((IXmlLineInfo)reader).LinePosition }; if (XamlFilePathAttribute.GetFilePathForObject(view) is string path) { VisualDiagnostics.RegisterSourceInfo(view, new Uri($"{path};assembly={view.GetType().GetTypeInfo().Assembly.GetName().Name}", UriKind.Relative), ((IXmlLineInfo)rootnode).LineNumber, ((IXmlLineInfo)rootnode).LinePosition); VisualDiagnostics.SendVisualTreeChanged(null, view); } XamlParser.ParseXaml(rootnode, reader); #pragma warning disable 0618 var doNotThrow = ResourceLoader.ExceptionHandler2 != null || Internals.XamlLoader.DoNotThrowOnExceptions; #pragma warning restore 0618 void ehandler(Exception e) => ResourceLoader.ExceptionHandler2?.Invoke((e, XamlFilePathAttribute.GetFilePathForObject(view))); Visit(rootnode, new HydrationContext { RootElement = view, RootAssembly = rootAssembly ?? view.GetType().GetTypeInfo().Assembly, ExceptionHandler = doNotThrow ? ehandler : (Action <Exception>)null }, useDesignProperties); break; } } }
public void Visit(ElementNode node, INode parentNode) { object value = null; var type = XamlParser.GetElementType(node.XmlType, node, Context.RootElement?.GetType().GetTypeInfo().Assembly, out XamlParseException xpe); if (xpe != null) { if (Context.ExceptionHandler != null) { Context.ExceptionHandler(xpe); return; } throw xpe; } Context.Types[node] = type; if (IsXaml2009LanguagePrimitive(node)) { value = CreateLanguagePrimitive(type, node); } else if (node.Properties.ContainsKey(XmlName.xArguments) || node.Properties.ContainsKey(XmlName.xFactoryMethod)) { value = CreateFromFactory(type, node); } else if ( type.GetTypeInfo() .DeclaredConstructors.Any( ci => ci.IsPublic && ci.GetParameters().Length != 0 && ci.GetParameters().All(pi => pi.CustomAttributes.Any(attr => attr.AttributeType == typeof(ParameterAttribute)))) && ValidateCtorArguments(type, node, out string ctorargname)) { value = CreateFromParameterizedConstructor(type, node); } else if (!type.GetTypeInfo().DeclaredConstructors.Any(ci => ci.IsPublic && ci.GetParameters().Length == 0) && !ValidateCtorArguments(type, node, out ctorargname)) { throw new XamlParseException($"The Property {ctorargname} is required to create a {type.FullName} object.", node); } else { //this is a trick as the DataTemplate parameterless ctor is internal, and we can't CreateInstance(..., false) on WP7 try { if (type == typeof(DataTemplate)) { value = new DataTemplate(); } if (type == typeof(ControlTemplate)) { value = new ControlTemplate(); } if (value == null && node.CollectionItems.Any() && node.CollectionItems.First() is ValueNode) { var serviceProvider = new XamlServiceProvider(node, Context); var converted = ((ValueNode)node.CollectionItems.First()).Value.ConvertTo(type, () => type.GetTypeInfo(), serviceProvider, out Exception exception); if (exception != null) { if (Context.ExceptionHandler != null) { Context.ExceptionHandler(exception); return; } throw exception; } if (converted != null && converted.GetType() == type) { value = converted; } } if (value == null) { try { value = Activator.CreateInstance(type); } catch (Exception e) when(e is TargetInvocationException || e is MemberAccessException) { value = XamlLoader.InstantiationFailedCallback?.Invoke(new XamlLoader.CallbackTypeInfo { XmlNamespace = node.XmlType.NamespaceUri, XmlTypeName = node.XmlType.Name }, type, e) ?? throw e; } } } catch (TargetInvocationException e) when(e.InnerException is XamlParseException || e.InnerException is XmlException) { throw e.InnerException; } catch (MissingMemberException mme) { throw new XamlParseException(mme.Message, node, mme); } } Values[node] = value; if (value is IMarkupExtension markup && (value is TypeExtension || value is StaticExtension || value is ArrayExtension)) { var serviceProvider = new XamlServiceProvider(node, Context); var visitor = new ApplyPropertiesVisitor(Context); foreach (var cnode in node.Properties.Values.ToList()) { cnode.Accept(visitor, node); } foreach (var cnode in node.CollectionItems) { cnode.Accept(visitor, node); } try { value = markup.ProvideValue(serviceProvider); } catch (Exception e) { var xamlpe = e as XamlParseException ?? new XamlParseException("Markup extension failed", serviceProvider, e); if (Context.ExceptionHandler != null) { Context.ExceptionHandler(xamlpe); } else { throw xamlpe; } } if (!node.Properties.TryGetValue(XmlName.xKey, out INode xKey)) { xKey = null; } node.Properties.Clear(); node.CollectionItems.Clear(); if (xKey != null) { node.Properties.Add(XmlName.xKey, xKey); } Values[node] = value; } if (value is BindableObject bindableValue && node.NameScopeRef != (parentNode as IElementNode)?.NameScopeRef) { NameScope.SetNameScope(bindableValue, node.NameScopeRef.NameScope); } if (XamlLoader.ValueCreatedCallback != null) { var name = node.XmlType.Name; if (name.Contains(":")) { name = name.Substring(name.LastIndexOf(':') + 1); } XamlLoader.ValueCreatedCallback(new XamlLoader.CallbackTypeInfo { XmlNamespace = node.XmlType.NamespaceUri, XmlTypeName = name }, value); } var assemblyName = (Context.RootAssembly ?? Context.RootElement?.GetType().GetTypeInfo().Assembly)?.GetName().Name; if (assemblyName != null && value != null && !value.GetType().GetTypeInfo().IsValueType&& XamlFilePathAttribute.GetFilePathForObject(Context.RootElement) is string path) { Diagnostics.VisualDiagnostics.RegisterSourceInfo(value, new Uri($"{path};assembly={assemblyName}", UriKind.Relative), ((IXmlLineInfo)node).LineNumber, ((IXmlLineInfo)node).LinePosition); } }
public void Visit(RootNode node, INode parentNode) { var rnode = (XamlLoader.RuntimeRootNode)node; Values[node] = rnode.Root; Context.Types[node] = rnode.Root.GetType(); if (rnode.Root is BindableObject bindable) { if (NameScope.GetNameScope(bindable) is INameScope existingNs) { node.NameScopeRef.NameScope = existingNs; } else { NameScope.SetNameScope(bindable, node.NameScopeRef?.NameScope); } } var assemblyName = (Context.RootAssembly ?? Context.RootElement.GetType().GetTypeInfo().Assembly)?.GetName().Name; if (rnode.Root != null && !rnode.Root.GetType().GetTypeInfo().IsValueType&& XamlFilePathAttribute.GetFilePathForObject(Context.RootElement) is string path) { Diagnostics.VisualDiagnostics.RegisterSourceInfo(rnode.Root, new Uri($"{path};assembly={assemblyName}", UriKind.Relative), ((IXmlLineInfo)node).LineNumber, ((IXmlLineInfo)node).LinePosition); } }
public static void SetPropertyValue(object xamlelement, XmlName propertyName, object value, object rootElement, INode node, HydrationContext context, IXmlLineInfo lineInfo) { var localName = propertyName.LocalName; var serviceProvider = new XamlServiceProvider(node, context); Exception xpe = null; var xKey = node is IElementNode && ((IElementNode)node).Properties.ContainsKey(XmlName.xKey) ? ((ValueNode)((IElementNode)node).Properties[XmlName.xKey]).Value as string : 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, attached, 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; } var assemblyName = (context.RootAssembly ?? rootElement.GetType().GetTypeInfo().Assembly)?.GetName().Name; //If it's a BindableProberty, SetValue if (xpe == null && TrySetValue(xamlelement, property, attached, value, lineInfo, serviceProvider, out xpe)) { if (!(node is ValueNode) && value != null && !value.GetType().GetTypeInfo().IsValueType&& XamlFilePathAttribute.GetFilePathForObject(context.RootElement) is string path) { VisualDiagnostics.RegisterSourceInfo(value, new Uri($"{path};assembly={assemblyName}", UriKind.Relative), ((IXmlLineInfo)node).LineNumber, ((IXmlLineInfo)node).LinePosition); } return; } //If we can assign that value to a normal property, let's do it if (xpe == null && TrySetProperty(xamlelement, localName, value, lineInfo, serviceProvider, context, out xpe)) { if (!(node is ValueNode) && value != null && !value.GetType().GetTypeInfo().IsValueType&& XamlFilePathAttribute.GetFilePathForObject(context.RootElement) is string path) { VisualDiagnostics.RegisterSourceInfo(value, new Uri($"{path};assembly={assemblyName}", UriKind.Relative), ((IXmlLineInfo)node).LineNumber, ((IXmlLineInfo)node).LinePosition); } return; } //If it's an already initialized property, add to it if (xpe == null && TryAddToProperty(xamlelement, propertyName, value, xKey, lineInfo, serviceProvider, context, out xpe)) { if (!(node is ValueNode) && value != null && !value.GetType().GetTypeInfo().IsValueType&& XamlFilePathAttribute.GetFilePathForObject(context.RootElement) is string path) { VisualDiagnostics.RegisterSourceInfo(value, new Uri($"{path};assembly={assemblyName}", UriKind.Relative), ((IXmlLineInfo)node).LineNumber, ((IXmlLineInfo)node).LinePosition); } return; } xpe = xpe ?? new XamlParseException($"Cannot assign property \"{localName}\": Property does not exist, or is not assignable, or mismatching type between value and property", lineInfo); if (context.ExceptionHandler != null) { context.ExceptionHandler(xpe); } else { throw xpe; } }
//Used by HotReload, do not change signature public static bool TrySetPropertyValue(object element, XmlName propertyName, string xKey, object value, object rootElement, IXmlLineInfo lineInfo, IServiceProvider serviceProvider, out Exception xpe) { var localName = propertyName.LocalName; xpe = null; var assemblyName = rootElement.GetType().GetTypeInfo().Assembly?.GetName().Name; void registerSourceInfo(object target, string path) => VisualDiagnostics.RegisterSourceInfo(target, new Uri($"{path};assembly={assemblyName}", UriKind.Relative), lineInfo.LineNumber, lineInfo.LinePosition); //If it's an attached BP, update elementType and propertyName var bpOwnerType = element.GetType(); var attached = GetRealNameAndType(ref bpOwnerType, propertyName.NamespaceURI, ref localName, rootElement, lineInfo); var property = GetBindableProperty(bpOwnerType, localName, lineInfo, false); //If the target is an event, connect if (xpe == null && TryConnectEvent(element, localName, attached, value, rootElement, lineInfo, out xpe)) { return(true); } //If Value is DynamicResource and it's a BP, SetDynamicResource if (xpe == null && TrySetDynamicResource(element, property, value, lineInfo, out xpe)) { return(true); } //If value is BindingBase, SetBinding if (xpe == null && TrySetBinding(element, property, localName, value, lineInfo, out var binding, out xpe)) { if (binding != null && XamlFilePathAttribute.GetFilePathForObject(rootElement) is string path) { registerSourceInfo(binding, path); } return(true); } //If it's a BindableProberty, SetValue if (xpe == null && TrySetValue(element, property, attached, value, lineInfo, serviceProvider, out xpe)) { if (value != null && !value.GetType().GetTypeInfo().IsValueType&& XamlFilePathAttribute.GetFilePathForObject(rootElement) is string path) { registerSourceInfo(value, path); } return(true); } //If we can assign that value to a normal property, let's do it if (xpe == null && TrySetProperty(element, localName, value, lineInfo, serviceProvider, rootElement, out xpe)) { if (value != null && !value.GetType().GetTypeInfo().IsValueType&& XamlFilePathAttribute.GetFilePathForObject(rootElement) is string path) { registerSourceInfo(value, path); } return(true); } //If it's an already initialized property, add to it if (xpe == null && TryAddToProperty(element, propertyName, value, xKey, lineInfo, serviceProvider, rootElement, out xpe)) { if (value != null && !value.GetType().GetTypeInfo().IsValueType&& XamlFilePathAttribute.GetFilePathForObject(rootElement) is string path) { registerSourceInfo(value, path); } return(true); } xpe = xpe ?? new XamlParseException($"Cannot assign property \"{localName}\": Property does not exist, or is not assignable, or mismatching type between value and property", lineInfo); return(false); }