From 0c20b4137783a7b2fcdca644e678e603035ff163 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Sat, 6 Feb 2016 16:02:27 +0100 Subject: [PATCH] Build XAML namespace registry dynamically. Each time a namespace is not found, look for any assemblies loaded since the last scan and scan them for XmlnsDefinitionAttribute. --- .../Context/PerspexNamespaceRegistry.cs | 114 ++++++++++++++++++ .../Context/PerspexRuntimeTypeSource.cs | 30 +---- src/Markup/Perspex.Markup.Xaml/OmniXAML | 2 +- .../Perspex.Markup.Xaml.csproj | 1 + 4 files changed, 118 insertions(+), 29 deletions(-) create mode 100644 src/Markup/Perspex.Markup.Xaml/Context/PerspexNamespaceRegistry.cs diff --git a/src/Markup/Perspex.Markup.Xaml/Context/PerspexNamespaceRegistry.cs b/src/Markup/Perspex.Markup.Xaml/Context/PerspexNamespaceRegistry.cs new file mode 100644 index 0000000000..bf3fc5265c --- /dev/null +++ b/src/Markup/Perspex.Markup.Xaml/Context/PerspexNamespaceRegistry.cs @@ -0,0 +1,114 @@ +// Copyright (c) The Perspex Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using OmniXaml.Builder; +using OmniXaml.Typing; +using Perspex.Controls; +using Perspex.Markup.Xaml.Templates; +using Perspex.Media; +using Perspex.Metadata; +using Perspex.Platform; +using Perspex.Styling; + +namespace Perspex.Markup.Xaml.Context +{ + public class PerspexNamespaceRegistry : INamespaceRegistry + { + private const string PerspexNs = "https://github.com/perspex"; + + private static readonly IEnumerable ForcedAssemblies = new[] + { + typeof(PerspexObject).GetTypeInfo().Assembly, + typeof(Control).GetTypeInfo().Assembly, + typeof(Style).GetTypeInfo().Assembly, + typeof(DataTemplate).GetTypeInfo().Assembly, + typeof(SolidColorBrush).GetTypeInfo().Assembly, + typeof(IValueConverter).GetTypeInfo().Assembly, + }; + + private List _namespaces = new List(); + private List _prefixes = new List(); + private List _scanned = new List(); + + public PerspexNamespaceRegistry() + { + ScanAssemblies(ForcedAssemblies); + ScanNewAssemblies(); + RegisterPrefix(new PrefixRegistration(string.Empty, PerspexNs)); + } + + public IEnumerable RegisteredPrefixes => _prefixes; + + public void AddNamespace(XamlNamespace xamlNamespace) + { + _namespaces.Add(xamlNamespace); + } + + public Namespace GetNamespace(string name) + { + var result = _namespaces.FirstOrDefault(x => x.Name == name); + + if (result == null) + { + ScanNewAssemblies(); + result = _namespaces.FirstOrDefault(x => x.Name == name); + } + + return result; + } + + public Namespace GetNamespaceByPrefix(string prefix) + { + var ns = _prefixes.FirstOrDefault(x => x.Prefix == prefix)?.Ns; + return (ns != null) ? GetNamespace(ns) : null; + } + + public void RegisterPrefix(PrefixRegistration prefixRegistration) + { + _prefixes.Add(prefixRegistration); + } + + private void ScanAssemblies(IEnumerable assemblies) + { + foreach (var assembly in assemblies) + { + var namespaces = assembly.GetCustomAttributes() + .Select(x => new { x.XmlNamespace, x.ClrNamespace }) + .GroupBy(x => x.XmlNamespace); + + foreach (var nsa in namespaces) + { + var xamlNamespace = _namespaces.FirstOrDefault(x => x.Name == nsa.Key); + + if (xamlNamespace == null) + { + xamlNamespace = new XamlNamespace(nsa.Key); + _namespaces.Add(xamlNamespace); + } + + var clrNamespaces = namespaces.SelectMany(x => x).Select(x => x.ClrNamespace); + xamlNamespace.Addresses.Add(new ConfiguredAssemblyWithNamespaces(assembly, clrNamespaces)); + } + + _scanned.Add(assembly); + } + } + + private void ScanNewAssemblies() + { + IEnumerable assemblies = PerspexLocator.Current + .GetService() + ?.GetLoadedAssemblies(); + + if (assemblies != null) + { + assemblies = assemblies.Except(_scanned); + ScanAssemblies(assemblies); + } + } + } +} diff --git a/src/Markup/Perspex.Markup.Xaml/Context/PerspexRuntimeTypeSource.cs b/src/Markup/Perspex.Markup.Xaml/Context/PerspexRuntimeTypeSource.cs index 51f0457fad..1fffb83814 100644 --- a/src/Markup/Perspex.Markup.Xaml/Context/PerspexRuntimeTypeSource.cs +++ b/src/Markup/Perspex.Markup.Xaml/Context/PerspexRuntimeTypeSource.cs @@ -34,14 +34,12 @@ namespace Perspex.Markup.Xaml.Context typeof(SolidColorBrush).GetTypeInfo().Assembly, typeof(IValueConverter).GetTypeInfo().Assembly, }; - - private const string PerspexNs = "https://github.com/perspex"; + private readonly RuntimeTypeSource inner; public PerspexRuntimeTypeSource(ITypeFactory typeFactory) { - var namespaceRegistry = CreateNamespaceRegistry(); - + var namespaceRegistry = new PerspexNamespaceRegistry(); var featureProvider = new TypeFeatureProvider(GetConverterProvider()); LoadFeatureProvider(featureProvider); var typeRepository = new PerspexTypeRepository(namespaceRegistry, typeFactory, featureProvider); @@ -93,30 +91,6 @@ namespace Perspex.Markup.Xaml.Context } } - private static INamespaceRegistry CreateNamespaceRegistry() - { - var xamlNamespaceRegistry = new NamespaceRegistry(); - - foreach (var nsa in - ScannedAssemblies - .Distinct() - .SelectMany(asm - => asm.GetCustomAttributes().Select(attr => new { asm, attr })) - .GroupBy(entry => entry.attr.XmlNamespace)) - { - var def = XamlNamespace.Map(nsa.Key) - .With(nsa.GroupBy(x => x.asm).Select( - a => Route.Assembly(a.Key) - .WithNamespaces(a.Select(entry => entry.attr.ClrNamespace).ToList()) - )); - xamlNamespaceRegistry.AddNamespace(def); - } - - xamlNamespaceRegistry.RegisterPrefix(new PrefixRegistration(string.Empty, PerspexNs)); - - return xamlNamespaceRegistry; - } - private static ITypeConverterProvider GetConverterProvider() { var typeConverterProvider = new TypeConverterProvider(); diff --git a/src/Markup/Perspex.Markup.Xaml/OmniXAML b/src/Markup/Perspex.Markup.Xaml/OmniXAML index c2ffcccc82..2b28639da1 160000 --- a/src/Markup/Perspex.Markup.Xaml/OmniXAML +++ b/src/Markup/Perspex.Markup.Xaml/OmniXAML @@ -1 +1 @@ -Subproject commit c2ffcccc82514d19adeb74220e0490ac480c7473 +Subproject commit 2b28639da15e5f43f4b713e0b115d1bb41679cc6 diff --git a/src/Markup/Perspex.Markup.Xaml/Perspex.Markup.Xaml.csproj b/src/Markup/Perspex.Markup.Xaml/Perspex.Markup.Xaml.csproj index e5a6bcedf1..eef6776375 100644 --- a/src/Markup/Perspex.Markup.Xaml/Perspex.Markup.Xaml.csproj +++ b/src/Markup/Perspex.Markup.Xaml/Perspex.Markup.Xaml.csproj @@ -42,6 +42,7 @@ +