public void XmlNamespaceMaps() { const string xaml = @"<Window xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation' xmlns:test='http://test' test:HasAttachableDp.MyDp='Bar' Content='{Binding (test:HasAttachableDp.MyProperty), RelativeSource={RelativeSource Self}}' />"; XamlTypeMapper mapper = new XamlTypeMapper(new string[0], new NamespaceMapEntry[] { new NamespaceMapEntry { XmlNamespace = "http://test", ClrNamespace = "Test.Elements", AssemblyName = "XamlTestClasses" } }); ParserContext pc = new ParserContext { XamlTypeMapper = mapper }; Window window = (Window)System.Windows.Markup.XamlReader.Parse(xaml, pc); window.Show(); object content = window.Content; window.Close(); Assert.AreEqual("Bar", content); }
public static ResourceDictionary GetDefaultStyles() { var resourceKeysType = typeof(ResourceKeys); var fieldInfos = resourceKeysType.GetFields(); var styleFragments = fieldInfos.Select(GenerateDefaultStyleFragment) .Where(item => item != null); var xaml = string.Format(CultureInfo.InvariantCulture, "<ResourceDictionary>\n{0}\n</ResourceDictionary>", string.Join("\n", styleFragments)); var xamlTypeMapper = new XamlTypeMapper(new string[0]); xamlTypeMapper.AddMappingProcessingInstruction("styles", resourceKeysType.Namespace, resourceKeysType.Assembly.FullName); var context = new ParserContext { XamlTypeMapper = xamlTypeMapper }; context.XmlnsDictionary.Add("", "http://schemas.microsoft.com/winfx/2006/xaml/presentation"); context.XmlnsDictionary.Add("x", "http://schemas.microsoft.com/winfx/2006/xaml"); context.XmlnsDictionary.Add("styles", "styles"); var resourceDictionary = (ResourceDictionary)XamlReader.Parse(xaml, context); resourceDictionary.Add(_defaultStylesKey, true); return(resourceDictionary); }
public override void WriteUnknownTagStart(XamlUnknownTagStartNode xamlUnknownTagStartNode) { string localElementFullName = string.Empty; NamespaceMapEntry[] namespaceMaps = XamlTypeMapper.GetNamespaceMapEntries(xamlUnknownTagStartNode.XmlNamespace); if (namespaceMaps != null && namespaceMaps.Length == 1 && namespaceMaps[0].LocalAssembly) { string ns = namespaceMaps[0].ClrNamespace; if (!string.IsNullOrEmpty(ns)) { ns += MarkupCompiler.DOT; } localElementFullName = ns + xamlUnknownTagStartNode.Value; } if (localElementFullName.Length > 0 && !_pass2) { // if local complex property bail out now and handle in 2nd pass when TypInfo is available int lastIndex = xamlUnknownTagStartNode.Value.LastIndexOf(MarkupCompiler.DOTCHAR); if (-1 == lastIndex) { _compiler.StartElement(ref _class, _subClass, ref _classModifier, null, localElementFullName); } } else { base.WriteUnknownTagStart(xamlUnknownTagStartNode); } }
public static ResourceDictionary GetDefaultStyles() { var resourceKeysType = typeof(ResourceKeys); var baseStyleKeys = resourceKeysType .GetFields() .Where(field => field.GetCustomAttributes <DefaultStyleAttribute>(false).Any()); var styleFragments = baseStyleKeys.Select(GenerateDefaultStyleFragment).ToList(); styleFragments.Add("<Style x:Key=\"{x:Static MenuItem.SeparatorStyleKey}\" TargetType=\"Separator\" BasedOn=\"{StaticResource {x:Static styles:ResourceKeys.MenuItemSeparatorStyle}}\" />"); var xaml = string.Format(CultureInfo.InvariantCulture, "<ResourceDictionary>\n{0}\n</ResourceDictionary>", string.Join("\n", styleFragments)); var xamlTypeMapper = new XamlTypeMapper(new string[0]); xamlTypeMapper.AddMappingProcessingInstruction("styles", resourceKeysType.Namespace ?? string.Empty, resourceKeysType.Assembly.FullName); var context = new ParserContext { XamlTypeMapper = xamlTypeMapper }; context.XmlnsDictionary.Add("", "http://schemas.microsoft.com/winfx/2006/xaml/presentation"); context.XmlnsDictionary.Add("x", "http://schemas.microsoft.com/winfx/2006/xaml"); context.XmlnsDictionary.Add("styles", "styles"); return((ResourceDictionary)XamlReader.Parse(xaml, context)); }
/// <summary> /// override for mapping instructions between clr and xml namespaces /// </summary> public override void WritePIMapping(XamlPIMappingNode xamlPIMappingNode) { if (!_pass2) { _compiler.AddUsing(xamlPIMappingNode.ClrNamespace); } // Local assembly! if ((xamlPIMappingNode.AssemblyName == null) || (xamlPIMappingNode.AssemblyName.Length == 0)) { xamlPIMappingNode.AssemblyName = _compiler.AssemblyName; bool addMapping = !XamlTypeMapper.PITable.Contains(xamlPIMappingNode.XmlNamespace) || ((ClrNamespaceAssemblyPair)XamlTypeMapper.PITable[xamlPIMappingNode.XmlNamespace]).LocalAssembly || string.IsNullOrEmpty(((ClrNamespaceAssemblyPair)XamlTypeMapper.PITable[xamlPIMappingNode.XmlNamespace]).AssemblyName); if (addMapping) { ClrNamespaceAssemblyPair namespaceMapping = new ClrNamespaceAssemblyPair(xamlPIMappingNode.ClrNamespace, xamlPIMappingNode.AssemblyName); namespaceMapping.LocalAssembly = true; XamlTypeMapper.PITable[xamlPIMappingNode.XmlNamespace] = namespaceMapping; XamlTypeMapper.InvalidateMappingCache(xamlPIMappingNode.XmlNamespace); if (!_pass2 && BamlRecordWriter != null) { BamlRecordWriter = null; } } } base.WritePIMapping(xamlPIMappingNode); }
private static XamlTypeMapper CreateXamlTypeMapper(Type viewModelType, Type viewType) { var xamlTypeMapper = new XamlTypeMapper(new string[0]); xamlTypeMapper.AddMappingProcessingInstruction("vm", viewModelType.Namespace, viewModelType.Assembly.GetName().Name); xamlTypeMapper.AddMappingProcessingInstruction("v", viewType.Namespace, viewType.Assembly.GetName().Name); return(xamlTypeMapper); }
public void TypeMapperWithMappingPI() { XamlTypeMapper typeMapper = new XamlTypeMapper(new string[0]); typeMapper.AddMappingProcessingInstruction("http://elements", "Test.Elements", "XamlTestClasses"); ParserContext pc = new ParserContext { XamlTypeMapper = typeMapper }; object result = System.Windows.Markup.XamlReader.Parse(ElementXaml, pc); Assert.IsInstanceOfType(typeof(Element), result); }
private XamlTypeMapper CreateXamlTypeMapper(Assembly assembly, IReadOnlyDictionary <Type, string> typeNamespaceProcessors) { var xamlTypeMapper = new XamlTypeMapper(new string[0]); foreach (var typeKeyValuePair in typeNamespaceProcessors) { xamlTypeMapper.AddMappingProcessingInstruction(typeKeyValuePair.Value, typeKeyValuePair.Key.Namespace, assembly.GetName().Name); } return(xamlTypeMapper); }
/// <summary> /// Creates the <see cref="DataTemplate"/> with the root node of the specified type. /// </summary> /// <param name="rootType">The type of the root node of the <see cref="DataTemplate"/> to create.</param> /// <returns>The <see cref="DataTemplate"/> with the root node of the <paramref name="rootType"/>.</returns> internal static DataTemplate CreateTemplate(Type rootType) { ParserContext context = new ParserContext(); XamlTypeMapper mapper = new XamlTypeMapper(Array.Empty <string>()); mapper.AddMappingProcessingInstruction(XmlNamespace, rootType.Namespace, rootType.Assembly.FullName); context.XamlTypeMapper = mapper; context.XmlnsDictionary.Add(string.Empty, NamespaceURI); context.XmlnsDictionary.Add(XmlNamespace, XmlNamespace); return(XamlReader.Parse(string.Format(Template, rootType.Name), context) as DataTemplate); }
/// <summary> /// override for handling a new xmlnamespace Uri /// </summary> public override void WriteNamespacePrefix(XamlXmlnsPropertyNode xamlXmlnsPropertyNode) { if (!_pass2) { List <ClrNamespaceAssemblyPair> cnap = XamlTypeMapper.GetClrNamespacePairFromCache(xamlXmlnsPropertyNode.XmlNamespace); if (cnap != null) { foreach (ClrNamespaceAssemblyPair u in cnap) { _compiler.AddUsing(u.ClrNamespace); } } } base.WriteNamespacePrefix(xamlXmlnsPropertyNode); }
public void addNamespace <T>(string name) { const string pattern = @"^\w[\w\d]*$"; if (!Regex.IsMatch(name, pattern)) { throw new ArgumentException($"Your namespace name is invalid. must match {pattern}. But you did '{name}' wich does not match exactly!"); } var viewType = typeof(T); var namespaceReference = viewType.Namespace ?? String.Empty; var assemblyName = viewType.Assembly.FullName; XamlTypeMapper.AddMappingProcessingInstruction(name, namespaceReference, assemblyName); XmlnsDictionary.Add(name, name); }
public void TypeMapperWithNamespaceEntry() { XamlTypeMapper typeMapper = new XamlTypeMapper(new string[0], new NamespaceMapEntry[] { new NamespaceMapEntry("http://elements", "XamlTestClasses", "Test.Elements") }); ParserContext pc = new ParserContext { XamlTypeMapper = typeMapper }; object result = System.Windows.Markup.XamlReader.Parse(ElementXaml, pc); Assert.IsInstanceOfType(typeof(Element), result); MemoryStream stream = new MemoryStream(Encoding.Default.GetBytes(ElementXaml)); result = new System.Windows.Markup.XamlReader().LoadAsync(stream, pc); Assert.IsInstanceOfType(typeof(Element), result); }
public override void WriteUnknownTagEnd(XamlUnknownTagEndNode xamlUnknownTagEndNode) { NamespaceMapEntry[] namespaceMaps = XamlTypeMapper.GetNamespaceMapEntries(xamlUnknownTagEndNode.XmlNamespace); bool localTag = namespaceMaps != null && namespaceMaps.Length == 1 && namespaceMaps[0].LocalAssembly; if (localTag && !_pass2) { // if local complex property bail out now and handle in 2nd pass when TypInfo is available int lastIndex = xamlUnknownTagEndNode.LocalName.LastIndexOf(MarkupCompiler.DOTCHAR); if (-1 == lastIndex) { _compiler.EndElement(_pass2); } } else { base.WriteUnknownTagEnd(xamlUnknownTagEndNode); } }
public XamlNamespace() { XamlTypeMapper = new XamlTypeMapper(new string[0]); XmlnsDictionary.Add(String.Empty, "http://schemas.microsoft.com/winfx/2006/xaml/presentation"); XmlnsDictionary.Add(X_DEFAILT_NAMESPACE, "http://schemas.microsoft.com/winfx/2006/xaml"); }
/// <summary> /// override of GetElementType /// </summary> public override bool GetElementType( XmlReader xmlReader, string localName, string namespaceUri, ref string assemblyName, ref string typeFullName, ref Type baseType, ref Type serializerType) { if (!ProcessedRootElement && namespaceUri.Equals(XamlReaderHelper.DefinitionNamespaceURI) && (localName.Equals(XamlReaderHelper.DefinitionCodeTag) || localName.Equals(XamlReaderHelper.DefinitionXDataTag))) { MarkupCompiler.ThrowCompilerException(SRID.DefinitionTagNotAllowedAtRoot, xmlReader.Prefix, localName); } bool foundElement = base.GetElementType(xmlReader, localName, namespaceUri, ref assemblyName, ref typeFullName, ref baseType, ref serializerType); if (!ProcessedRootElement) { int count = xmlReader.AttributeCount; // save reader's position, to be restored later string attrName = (xmlReader.NodeType == XmlNodeType.Attribute) ? xmlReader.Name : null; _isRootTag = true; _class = string.Empty; _subClass = string.Empty; ProcessedRootElement = true; XamlTypeMapper.IsProtectedAttributeAllowed = false; xmlReader.MoveToFirstAttribute(); while (--count >= 0) { string attribNamespaceURI = xmlReader.LookupNamespace(xmlReader.Prefix); if (attribNamespaceURI != null && attribNamespaceURI.Equals(XamlReaderHelper.DefinitionNamespaceURI)) { MarkupCompiler.DefinitionNSPrefix = xmlReader.Prefix; if (xmlReader.LocalName == CLASS) { _class = xmlReader.Value.Trim(); if (_class == string.Empty) { // flag an error for processing later in WriteDefAttribute _class = MarkupCompiler.DOT; } else { // flag this so that the Type Mapper can allow protected // attributes on the markup sub-classed root element only. XamlTypeMapper.IsProtectedAttributeAllowed = true; } } else if (xmlReader.LocalName == XamlReaderHelper.DefinitionTypeArgs) { string genericName = _compiler.GetGenericTypeName(localName, xmlReader.Value); foundElement = base.GetElementType(xmlReader, genericName, namespaceUri, ref assemblyName, ref typeFullName, ref baseType, ref serializerType); if (!foundElement) { NamespaceMapEntry[] namespaceMaps = XamlTypeMapper.GetNamespaceMapEntries(namespaceUri); bool isLocal = namespaceMaps != null && namespaceMaps.Length == 1 && namespaceMaps[0].LocalAssembly; if (!isLocal) { MarkupCompiler.ThrowCompilerException(SRID.UnknownGenericType, MarkupCompiler.DefinitionNSPrefix, xmlReader.Value, localName); } } } else if (xmlReader.LocalName == SUBCLASS) { _subClass = xmlReader.Value.Trim(); if (_subClass == string.Empty) { // flag an error for processing later in WriteDefAttribute _subClass = MarkupCompiler.DOT; } else { _compiler.ValidateFullSubClassName(ref _subClass); } } else if (xmlReader.LocalName == CLASSMODIFIER) { if (!_pass2) { _classModifier = xmlReader.Value.Trim(); if (_classModifier == string.Empty) { // flag an error for processing later in WriteDefAttribute _classModifier = MarkupCompiler.DOT; } } else { // This direct comparison is ok to do in pass2 as it has already been validated in pass1. // This is to avoid a costly instantiation of the CodeDomProvider in pass2. _isInternalRoot = string.Compare("public", xmlReader.Value.Trim(), StringComparison.OrdinalIgnoreCase) != 0; } } } xmlReader.MoveToNextAttribute(); } if (namespaceUri.Equals(XamlReaderHelper.DefinitionNamespaceURI)) { xmlReader.MoveToElement(); } else { if (attrName == null) { xmlReader.MoveToFirstAttribute(); } else { xmlReader.MoveToAttribute(attrName); } } } else if (!_compiler.IsBamlNeeded && !_compiler.ProcessingRootContext && _compiler.IsCompilingEntryPointClass && xmlReader.Depth > 0) { if ((!localName.Equals(MarkupCompiler.CODETAG) && !localName.Equals(MarkupCompiler.CODETAG + "Extension")) || !namespaceUri.Equals(XamlReaderHelper.DefinitionNamespaceURI)) { _compiler.IsBamlNeeded = true; } } return(foundElement); }
public override void WriteUnknownAttribute(XamlUnknownAttributeNode xamlUnknownAttributeNode) { bool localAttrib = false; string localTagFullName = string.Empty; string localAttribName = xamlUnknownAttributeNode.Name; NamespaceMapEntry[] namespaceMaps = null; MemberInfo miKnownEvent = null; if (xamlUnknownAttributeNode.OwnerTypeFullName.Length > 0) { // These are attributes on a local tag ... localTagFullName = xamlUnknownAttributeNode.OwnerTypeFullName; localAttrib = true; } else { // These are attributes on a non-local tag ... namespaceMaps = XamlTypeMapper.GetNamespaceMapEntries(xamlUnknownAttributeNode.XmlNamespace); localAttrib = namespaceMaps != null && namespaceMaps.Length == 1 && namespaceMaps[0].LocalAssembly; } if (localAttrib && !_pass2) { // ... and if there are any periods in the attribute name, then ... int lastIndex = localAttribName.LastIndexOf(MarkupCompiler.DOTCHAR); if (-1 != lastIndex) { // ... these might be attached props or events defined by a locally defined component, // but being set on this non-local tag. TypeAndSerializer typeAndSerializer = null; string ownerTagName = localAttribName.Substring(0, lastIndex); if (namespaceMaps != null) { if (namespaceMaps.Length == 1 && namespaceMaps[0].LocalAssembly) { // local prop on a known tag localTagFullName = namespaceMaps[0].ClrNamespace + MarkupCompiler.DOT + ownerTagName; } } else { typeAndSerializer = XamlTypeMapper.GetTypeOnly(xamlUnknownAttributeNode.XmlNamespace, ownerTagName); if (typeAndSerializer != null) { // known local attribute on a local tag Type ownerTagType = typeAndSerializer.ObjectType; localTagFullName = ownerTagType.FullName; localAttribName = localAttribName.Substring(lastIndex + 1); // See if attached event first miKnownEvent = ownerTagType.GetMethod(MarkupCompiler.ADD + localAttribName + MarkupCompiler.HANDLER, BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy); if (miKnownEvent == null) { // Not an attached event, so try for a clr event. miKnownEvent = ownerTagType.GetEvent(localAttribName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.FlattenHierarchy); } if (miKnownEvent != null) { if (_events == null) { _events = new ArrayList(); } _events.Add(new MarkupCompiler.MarkupEventInfo(xamlUnknownAttributeNode.Value, localAttribName, miKnownEvent, xamlUnknownAttributeNode.LineNumber)); WriteConnectionId(); } } else { namespaceMaps = XamlTypeMapper.GetNamespaceMapEntries(xamlUnknownAttributeNode.XmlNamespace); if (namespaceMaps != null && namespaceMaps.Length == 1 && namespaceMaps[0].LocalAssembly) { // local prop on local tag localTagFullName = namespaceMaps[0].ClrNamespace + MarkupCompiler.DOT + ownerTagName; } else { // unknown prop on local tag -- Error! localTagFullName = string.Empty; } } } if (typeAndSerializer == null) { localAttribName = localAttribName.Substring(lastIndex + 1); } } // else if it is an unknown non-attached prop on a non-local tag -- instant error! } if (localTagFullName.Length > 0 && !_pass2) { if (xamlUnknownAttributeNode.AttributeUsage == BamlAttributeUsage.RuntimeName) { string attributeValue = xamlUnknownAttributeNode.Value; Debug.Assert(_name == null && _nameField == null, "Name has already been set"); _nameField = _compiler.AddNameField(attributeValue, xamlUnknownAttributeNode.LineNumber, xamlUnknownAttributeNode.LinePosition); _name = attributeValue; if (_nameField != null) { WriteConnectionId(); } } else if (localAttribName.Equals(STARTUPURI) && _compiler.IsCompilingEntryPointClass) { // if Application.StartuoUri property then don't bamlize, but gen code since // this is better for perf as Application is not a DO. PropertyInfo pi = KnownTypes.Types[(int)KnownElements.Application].GetProperty(localAttribName); _compiler.AddApplicationProperty(pi, xamlUnknownAttributeNode.Value, xamlUnknownAttributeNode.LineNumber); return; } else if (miKnownEvent == null) { // This may or may not be a local event, but there is no way to know in Pass1. // So we prepare for the worst case sceanrio and assume it may be one so that // the Xaml compiler can generate the CreateDelegate code. _compiler.HasLocalEvent = true; } } else { base.WriteUnknownAttribute(xamlUnknownAttributeNode); } _compiler.IsBamlNeeded = true; }
/// <summary> /// Finds the <see cref="FrameworkElement"/> a specific style is based on. /// </summary> /// <param name="resourceDictionaryUri">The resource dictionary URI.</param> /// <param name="styleKey">The style key.</param> /// <returns> /// <see cref="Type"/> or <c>null</c> if the style is not based on a <see cref="FrameworkElement"/>. /// </returns> /// <exception cref="ArgumentNullException">The <paramref name="resourceDictionaryUri"/> is <c>null</c>.</exception> /// <exception cref="ArgumentNullException">The <paramref name="styleKey"/> is <c>null</c>.</exception> /// <remarks> /// This method is introduced due to the lack of the ability to use DynamicResource for the BasedOn property when /// defining styles inside a derived theme. /// Should be used in combination with the <see cref="RecreateDefaultStylesBasedOnTheme"/> method. /// </remarks> private static Type FindFrameworkElementStyleIsBasedOn(Uri resourceDictionaryUri, string styleKey) { Argument.IsNotNull("resourceDictionaryUri", resourceDictionaryUri); Argument.IsNotNull("styleKey", styleKey); if (_styleToFrameworkElementTypeCache.ContainsKey(styleKey)) { return(_styleToFrameworkElementTypeCache[styleKey]); } try { XmlDocument doc; if (_resourceDictionaryCache.ContainsKey(resourceDictionaryUri)) { doc = _resourceDictionaryCache[resourceDictionaryUri]; } else { StreamResourceInfo streamResourceInfo = Application.GetResourceStream(resourceDictionaryUri); var reader = new XmlBamlReader(streamResourceInfo.Stream); doc = new XmlDocument(); doc.Load(reader); _resourceDictionaryCache.Add(resourceDictionaryUri, doc); } #region Create xml namespace manager // Create namespace manager (all namespaces are required) var xmlNamespaceManager = new XmlNamespaceManager(doc.NameTable); foreach (XmlAttribute namespaceAttribute in doc.DocumentElement.Attributes) { // Clean up namespace (remove xmlns prefix) string xmlNamespace = namespaceAttribute.Name.Replace("xmlns", "").TrimStart(new char[] { ':' }); xmlNamespaceManager.AddNamespace(xmlNamespace, namespaceAttribute.Value); } // Add a dummy node xmlNamespaceManager.AddNamespace("x", "http://schemas.microsoft.com/winfx/2006/xaml"); xmlNamespaceManager.AddNamespace("ctl", "http://schemas.microsoft.com/winfx/2006/xaml/presentation"); #endregion string xpath = string.Format("/ctl:ResourceDictionary/ctl:Style[@x:Key='{0}']/@BasedOn", styleKey); var xmlAttribute = doc.SelectSingleNode(xpath, xmlNamespaceManager) as XmlAttribute; if (xmlAttribute == null) { Log.Warning("Style '{0}' does not have the 'BasedOn' attribute defined", styleKey); _styleToFrameworkElementTypeCache.Add(styleKey, null); return(null); } string basedOnValue = xmlAttribute.Value; basedOnValue = basedOnValue.Replace("StaticResource", ""); basedOnValue = basedOnValue.Replace("x:Type", "").Trim(new[] { ' ', '{', '}' }); #region Create xml type mapper var xamlTypeMapper = new XamlTypeMapper(new[] { "PresentationFramework" }); foreach (XmlAttribute namespaceAttribute in doc.DocumentElement.Attributes) { string xmlNamespace = namespaceAttribute.Name.Replace("xmlns", "").TrimStart(new char[] { ':' }); string value = namespaceAttribute.Value; string clrNamespace = value; string assemblyName = string.Empty; if (clrNamespace.StartsWith("clr-namespace:")) { // We have a hit (formatting is normally one of the 2 below): // * clr-namespace:[NAMESPACE] // * clr-namespace:[NAMESPACE];assembly=[ASSEMBLY] if (clrNamespace.Contains(";")) { clrNamespace = clrNamespace.Split(new char[] { ';' })[0]; } clrNamespace = clrNamespace.Replace("clr-namespace:", ""); if (value.Contains(";")) { assemblyName = value.Split(new char[] { ';' })[1].Replace("assembly:", ""); } xamlTypeMapper.AddMappingProcessingInstruction(xmlNamespace, clrNamespace, assemblyName); } } #endregion string[] splittedType = basedOnValue.Split(new[] { ':' }); string typeNamespace = (splittedType.Length == 2) ? splittedType[0] : "http://schemas.microsoft.com/winfx/2006/xaml/presentation"; string typeName = (splittedType.Length == 2) ? splittedType[1] : splittedType[0]; var type = xamlTypeMapper.GetType(typeNamespace, typeName); if (type == null) { _styleToFrameworkElementTypeCache.Add(styleKey, null); return(null); } Log.Debug("Style '{0}' is based on type '{1}'", styleKey, type); if ((type == typeof(FrameworkElement)) || type.IsSubclassOf(typeof(FrameworkElement))) { _styleToFrameworkElementTypeCache.Add(styleKey, type); return(type); } _styleToFrameworkElementTypeCache.Add(styleKey, null); return(null); } catch (Exception ex) { Log.Error(ex, "Failed to find the framework element where style '{0}' is based on", styleKey); return(null); } }
/// <summary> /// Finds the <see cref="FrameworkElement"/> a specific style is based on. /// </summary> /// <param name="resourceDictionaryUri">The resource dictionary URI.</param> /// <param name="styleKey">The style key.</param> /// <returns> /// <see cref="Type"/> or <c>null</c> if the style is not based on a <see cref="FrameworkElement"/>. /// </returns> /// <exception cref="ArgumentNullException">The <paramref name="resourceDictionaryUri"/> is <c>null</c>.</exception> /// <exception cref="ArgumentNullException">The <paramref name="styleKey"/> is <c>null</c>.</exception> /// <remarks> /// This method is introduced due to the lack of the ability to use DynamicResource for the BasedOn property when /// defining styles inside a derived theme. /// Should be used in combination with the <see cref="RecreateDefaultStylesBasedOnTheme"/> method. /// </remarks> private static Type FindFrameworkElementStyleIsBasedOn(Uri resourceDictionaryUri, string styleKey) { Argument.IsNotNull("resourceDictionaryUri", resourceDictionaryUri); Argument.IsNotNull("styleKey", styleKey); return(_styleToFrameworkElementTypeCache.GetFromCacheOrFetch(styleKey, () => { try { var xmlDocInfo = GetResourceXmlDocument(resourceDictionaryUri); var doc = xmlDocInfo.Item1; var xmlNamespaceManager = xmlDocInfo.Item2; var xpath = string.Format("/ctl:ResourceDictionary/ctl:Style[@x:Key='{0}']/@BasedOn", styleKey); var xmlAttribute = doc.SelectSingleNode(xpath, xmlNamespaceManager) as XmlAttribute; if (xmlAttribute == null) { Log.Warning("Style '{0}' does not have the 'BasedOn' attribute defined", styleKey); return null; } var basedOnValue = xmlAttribute.Value; basedOnValue = basedOnValue.Replace("StaticResource", string.Empty); basedOnValue = basedOnValue.Replace("x:Type", string.Empty).Trim(' ', '{', '}'); #region Create xml type mapper var xamlTypeMapper = new XamlTypeMapper(new[] { "PresentationFramework" }); foreach (XmlAttribute namespaceAttribute in doc.DocumentElement.Attributes) { var xmlNamespace = namespaceAttribute.Name.Replace("xmlns", string.Empty).TrimStart(':'); var value = namespaceAttribute.Value; var clrNamespace = value; var assemblyName = string.Empty; if (clrNamespace.StartsWith("clr-namespace:")) { // We have a hit (formatting is normally one of the 2 below): // * clr-namespace:[NAMESPACE] // * clr-namespace:[NAMESPACE];assembly=[ASSEMBLY] if (clrNamespace.Contains(";")) { clrNamespace = clrNamespace.Split(';')[0]; } clrNamespace = clrNamespace.Replace("clr-namespace:", string.Empty); if (value.Contains(";")) { assemblyName = value.Split(';')[1].Replace("assembly:", string.Empty); } xamlTypeMapper.AddMappingProcessingInstruction(xmlNamespace, clrNamespace, assemblyName); } } #endregion var splittedType = basedOnValue.Split(':'); var typeNamespace = (splittedType.Length == 2) ? splittedType[0] : "http://schemas.microsoft.com/winfx/2006/xaml/presentation"; var typeName = (splittedType.Length == 2) ? splittedType[1] : splittedType[0]; var type = xamlTypeMapper.GetType(typeNamespace, typeName); if (type == null) { return null; } Log.Debug("Style '{0}' is based on type '{1}'", styleKey, type); if ((type == typeof(FrameworkElement)) || type.IsSubclassOf(typeof(FrameworkElement))) { return type; } return null; } catch (Exception ex) { Log.Error(ex, "Failed to find the framework element where style '{0}' is based on", styleKey); return null; } })); }