Browse Source

initial portable xaml support attempt with datatemplate working and namespace support

donandren 8 years ago
parent
commit
d42e6d02cb
21 changed files with 1105 additions and 231 deletions
  1. 1 0
      src/Avalonia.Base/Avalonia.Base.csproj
  2. 15 0
      src/Avalonia.Base/Metadata/TemplateContent.cs
  3. 14 2
      src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj
  4. 8 222
      src/Markup/Avalonia.Markup.Xaml/AvaloniaXamlLoader.cs
  5. 227 0
      src/Markup/Avalonia.Markup.Xaml/AvaloniaXamlLoaderOmniXaml.cs
  6. 219 0
      src/Markup/Avalonia.Markup.Xaml/AvaloniaXamlLoaderPortableXaml.cs
  7. 2 0
      src/Markup/Avalonia.Markup.Xaml/Context/AvaloniaObjectAssembler.cs
  8. 2 0
      src/Markup/Avalonia.Markup.Xaml/Context/AvaloniaParserFactory.cs
  9. 1 1
      src/Markup/Avalonia.Markup.Xaml/Context/AvaloniaTypeFeatureProvider.cs
  10. 69 0
      src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaMemberAttributeProvider.cs
  11. 56 0
      src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaNameScope.cs
  12. 147 0
      src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaRuntimeTypeProvider.cs
  13. 91 0
      src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaTypeAttributeProvider.cs
  14. 101 0
      src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaXamlObjectWriter.cs
  15. 70 0
      src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaXamlSchemaContext.cs
  16. 7 3
      src/Markup/Avalonia.Markup.Xaml/Templates/DataTemplate.cs
  17. 29 2
      src/Markup/Avalonia.Markup.Xaml/Templates/TemplateContent.cs
  18. 22 1
      src/Markup/Avalonia.Markup.Xaml/Templates/TemplateLoader.cs
  19. 1 0
      src/Markup/Avalonia.Markup.Xaml/packages.config
  20. 11 0
      src/Markup/Avalonia.Markup/Avalonia.Markup.csproj
  21. 12 0
      src/Markup/Avalonia.Markup/packages.config

+ 1 - 0
src/Avalonia.Base/Avalonia.Base.csproj

@@ -70,6 +70,7 @@
     <Compile Include="Logging\LogArea.cs" />
     <Compile Include="Logging\LogEventLevel.cs" />
     <Compile Include="Logging\Logger.cs" />
+    <Compile Include="Metadata\TemplateContent.cs" />
     <Compile Include="Metadata\DependsOnAttribute.cs" />
     <Compile Include="Metadata\ContentAttribute.cs" />
     <Compile Include="AvaloniaDisposable.cs" />

+ 15 - 0
src/Avalonia.Base/Metadata/TemplateContent.cs

@@ -0,0 +1,15 @@
+// Copyright (c) The Avalonia Project. All rights reserved.
+// Licensed under the MIT license. See licence.md file in the project root for full license information.
+
+using System;
+
+namespace Avalonia.Metadata
+{
+    /// <summary>
+    /// Defines the property that contains the object's content in markup.
+    /// </summary>
+    [AttributeUsage(AttributeTargets.Property)]
+    public class TemplateContentAttribute : Attribute
+    {
+    }
+}

+ 14 - 2
src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj

@@ -21,7 +21,7 @@
     <DebugType>full</DebugType>
     <Optimize>false</Optimize>
     <OutputPath>bin\Debug\</OutputPath>
-    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <DefineConstants>TRACE;DEBUG;OMNIXAML_no</DefineConstants>
     <ErrorReport>prompt</ErrorReport>
     <WarningLevel>4</WarningLevel>
     <NoWarn>CS1591</NoWarn>
@@ -40,6 +40,13 @@
     <Compile Include="..\..\Shared\SharedAssemblyInfo.cs">
       <Link>Properties\SharedAssemblyInfo.cs</Link>
     </Compile>
+    <Compile Include="AvaloniaXamlLoaderPortableXaml.cs" />
+    <Compile Include="AvaloniaXamlLoader.cs" />
+    <Compile Include="PortableXaml\AvaloniaMemberAttributeProvider.cs" />
+    <Compile Include="PortableXaml\AvaloniaNameScope.cs" />
+    <Compile Include="PortableXaml\AvaloniaXamlObjectWriter.cs" />
+    <Compile Include="PortableXaml\AvaloniaRuntimeTypeProvider.cs" />
+    <Compile Include="PortableXaml\AvaloniaXamlSchemaContext.cs" />
     <Compile Include="Context\NameScopeWrapper.cs" />
     <Compile Include="Context\AvaloniaAttachableXamlMember.cs" />
     <Compile Include="Context\AvaloniaLifeCycleListener.cs" />
@@ -266,8 +273,9 @@
     <Compile Include="OmniXAML\Source\OmniXaml\XmlParser.cs" />
     <Compile Include="Parsers\SelectorGrammar.cs" />
     <Compile Include="Parsers\SelectorParser.cs" />
+    <Compile Include="PortableXaml\AvaloniaTypeAttributeProvider.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
-    <Compile Include="AvaloniaXamlLoader.cs" />
+    <Compile Include="AvaloniaXamlLoaderOmniXaml.cs" />
     <Compile Include="Styling\StyleInclude.cs" />
     <Compile Include="Templates\ControlTemplate.cs" />
     <Compile Include="Templates\DataTemplate.cs" />
@@ -322,6 +330,10 @@
     </ProjectReference>
   </ItemGroup>
   <ItemGroup>
+    <Reference Include="Portable.Xaml, Version=0.15.0.0, Culture=neutral, PublicKeyToken=ba4456acace7dab7, processorArchitecture=MSIL">
+      <HintPath>..\..\..\packages\Portable.Xaml.0.15.0\lib\portable-net45+win+wpa81+wp80+MonoAndroid10+xamarinios10+MonoTouch10\Portable.Xaml.dll</HintPath>
+      <Private>True</Private>
+    </Reference>
     <Reference Include="Sprache, Version=2.1.0.0, Culture=neutral, processorArchitecture=MSIL">
       <HintPath>..\..\..\packages\Sprache.2.1.0\lib\netstandard1.0\Sprache.dll</HintPath>
     </Reference>

+ 8 - 222
src/Markup/Avalonia.Markup.Xaml/AvaloniaXamlLoader.cs

@@ -1,225 +1,11 @@
-// Copyright (c) The Avalonia 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.IO;
-using System.Reflection;
-using System.Text;
-using OmniXaml;
-using Avalonia.Platform;
-using Avalonia.Markup.Xaml.Context;
-using Avalonia.Markup.Xaml.Styling;
-using OmniXaml.ObjectAssembler;
-using Avalonia.Controls;
-using Avalonia.Markup.Xaml.Data;
-
-namespace Avalonia.Markup.Xaml
+namespace Avalonia.Markup.Xaml
 {
-    /// <summary>
-    /// Loads XAML for a avalonia application.
-    /// </summary>
-    public class AvaloniaXamlLoader : XmlLoader
+    public class AvaloniaXamlLoader :
+#if OMNIXAML
+        AvaloniaXamlLoaderOmniXaml
+#else
+        AvaloniaXamlLoaderPortableXaml
+#endif
     {
-        private static AvaloniaParserFactory s_parserFactory;
-        private static IInstanceLifeCycleListener s_lifeCycleListener = new AvaloniaLifeCycleListener();
-        private static Stack<Uri> s_uriStack = new Stack<Uri>();
-
-        /// <summary>
-        /// Initializes a new instance of the <see cref="AvaloniaXamlLoader"/> class.
-        /// </summary>
-        public AvaloniaXamlLoader()
-            : this(GetParserFactory())
-        {
-        }
-
-        /// <summary>
-        /// Initializes a new instance of the <see cref="AvaloniaXamlLoader"/> class.
-        /// </summary>
-        /// <param name="xamlParserFactory">The parser factory to use.</param>
-        public AvaloniaXamlLoader(IParserFactory xamlParserFactory)
-            : base(xamlParserFactory)
-        {
-        }
-
-        /// <summary>
-        /// Gets the URI of the XAML file currently being loaded.
-        /// </summary>
-        /// <remarks>
-        /// TODO: Making this internal for now as I'm not sure that this is the correct
-        /// thing to do, but its needed by <see cref="StyleInclude"/> to get the URL of
-        /// the currently loading XAML file, as we can't use the OmniXAML parsing context
-        /// there. Maybe we need a way to inject OmniXAML context into the objects its
-        /// constructing?
-        /// </remarks>
-        internal static Uri UriContext => s_uriStack.Count > 0 ? s_uriStack.Peek() : null;
-
-        /// <summary>
-        /// Loads the XAML into a Avalonia component.
-        /// </summary>
-        /// <param name="obj">The object to load the XAML into.</param>
-        public static void Load(object obj)
-        {
-            Contract.Requires<ArgumentNullException>(obj != null);
-
-            var loader = new AvaloniaXamlLoader();
-            loader.Load(obj.GetType(), obj);
-        }
-
-        /// <summary>
-        /// Loads the XAML for a type.
-        /// </summary>
-        /// <param name="type">The type.</param>
-        /// <param name="rootInstance">
-        /// The optional instance into which the XAML should be loaded.
-        /// </param>
-        /// <returns>The loaded object.</returns>
-        public object Load(Type type, object rootInstance = null)
-        {
-            Contract.Requires<ArgumentNullException>(type != null);
-
-            // HACK: Currently Visual Studio is forcing us to change the extension of xaml files
-            // in certain situations, so we try to load .xaml and if that's not found we try .xaml.
-            // Ideally we'd be able to use .xaml everywhere
-            var assetLocator = AvaloniaLocator.Current.GetService<IAssetLoader>();
-
-            if (assetLocator == null)
-            {
-                throw new InvalidOperationException(
-                    "Could not create IAssetLoader : maybe Application.RegisterServices() wasn't called?");
-            }
-
-            foreach (var uri in GetUrisFor(type))
-            {
-                if (assetLocator.Exists(uri))
-                {
-                    using (var stream = assetLocator.Open(uri))
-                    {
-                        var initialize = rootInstance as ISupportInitialize;
-                        initialize?.BeginInit();
-                        return Load(stream, rootInstance, uri);
-                    }
-                }
-            }
-
-            throw new FileNotFoundException("Unable to find view for " + type.FullName);
-        }
-
-        /// <summary>
-        /// Loads XAML from a URI.
-        /// </summary>
-        /// <param name="uri">The URI of the XAML file.</param>
-        /// <param name="baseUri">
-        /// A base URI to use if <paramref name="uri"/> is relative.
-        /// </param>
-        /// <param name="rootInstance">
-        /// The optional instance into which the XAML should be loaded.
-        /// </param>
-        /// <returns>The loaded object.</returns>
-        public object Load(Uri uri, Uri baseUri = null, object rootInstance = null)
-        {
-            Contract.Requires<ArgumentNullException>(uri != null);
-
-            var assetLocator = AvaloniaLocator.Current.GetService<IAssetLoader>();
-
-            if (assetLocator == null)
-            {
-                throw new InvalidOperationException(
-                    "Could not create IAssetLoader : maybe Application.RegisterServices() wasn't called?");
-            }
-
-            using (var stream = assetLocator.Open(uri, baseUri))
-            {
-                return Load(stream, rootInstance, uri);
-            }
-        }
-
-        /// <summary>
-        /// Loads XAML from a string.
-        /// </summary>
-        /// <param name="xaml">The string containing the XAML.</param>
-        /// <param name="rootInstance">
-        /// The optional instance into which the XAML should be loaded.
-        /// </param>
-        /// <returns>The loaded object.</returns>
-        public object Load(string xaml, object rootInstance = null)
-        {
-            Contract.Requires<ArgumentNullException>(xaml != null);
-
-            using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(xaml)))
-            {
-                return Load(stream, rootInstance);
-            }
-        }
-
-        /// <summary>
-        /// Loads XAML from a stream.
-        /// </summary>
-        /// <param name="stream">The stream containing the XAML.</param>
-        /// <param name="rootInstance">
-        /// The optional instance into which the XAML should be loaded.
-        /// </param>
-        /// <param name="uri">The URI of the XAML</param>
-        /// <returns>The loaded object.</returns>
-        public object Load(Stream stream, object rootInstance = null, Uri uri = null)
-        {
-            try
-            {
-                if (uri != null)
-                {
-                    s_uriStack.Push(uri);
-                }
-
-                var result = base.Load(stream, new Settings
-                {
-                    RootInstance = rootInstance,
-                    InstanceLifeCycleListener = s_lifeCycleListener,
-                    ParsingContext = new Dictionary<string, object>
-                    {
-                        { "Uri", uri }
-                    }
-                });
-
-                var topLevel = result as TopLevel;
-
-                if (topLevel != null)
-                {
-                    DelayedBinding.ApplyBindings(topLevel);
-                }
-
-                return result;
-            }
-            finally
-            {
-                if (uri != null)
-                {
-                    s_uriStack.Pop();
-                }
-            }
-        }
-
-        private static AvaloniaParserFactory GetParserFactory()
-        {
-            if (s_parserFactory == null)
-            {
-                s_parserFactory = new AvaloniaParserFactory();
-            }
-
-            return s_parserFactory;
-        }
-
-        /// <summary>
-        /// Gets the URI for a type.
-        /// </summary>
-        /// <param name="type">The type.</param>
-        /// <returns>The URI.</returns>
-        private static IEnumerable<Uri> GetUrisFor(Type type)
-        {
-            var asm = type.GetTypeInfo().Assembly.GetName().Name;
-            var typeName = type.FullName;
-            yield return new Uri("resm:" + typeName + ".xaml?assembly=" + asm);
-            yield return new Uri("resm:" + typeName + ".paml?assembly=" + asm);
-
-        }
     }
-}
+}

+ 227 - 0
src/Markup/Avalonia.Markup.Xaml/AvaloniaXamlLoaderOmniXaml.cs

@@ -0,0 +1,227 @@
+// Copyright (c) The Avalonia 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.IO;
+using System.Reflection;
+using System.Text;
+using OmniXaml;
+using Avalonia.Platform;
+using Avalonia.Markup.Xaml.Context;
+using Avalonia.Markup.Xaml.Styling;
+using OmniXaml.ObjectAssembler;
+using Avalonia.Controls;
+using Avalonia.Markup.Xaml.Data;
+
+namespace Avalonia.Markup.Xaml
+{
+#if OMNIXAML
+    /// <summary>
+    /// Loads XAML for a avalonia application.
+    /// </summary>
+    public class AvaloniaXamlLoaderOmniXaml : XmlLoader
+    {
+        private static AvaloniaParserFactory s_parserFactory;
+        private static IInstanceLifeCycleListener s_lifeCycleListener = new AvaloniaLifeCycleListener();
+        private static Stack<Uri> s_uriStack = new Stack<Uri>();
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="AvaloniaXamlLoader"/> class.
+        /// </summary>
+        public AvaloniaXamlLoaderOmniXaml()
+            : this(GetParserFactory())
+        {
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="AvaloniaXamlLoader"/> class.
+        /// </summary>
+        /// <param name="xamlParserFactory">The parser factory to use.</param>
+        public AvaloniaXamlLoaderOmniXaml(IParserFactory xamlParserFactory)
+            : base(xamlParserFactory)
+        {
+        }
+
+        /// <summary>
+        /// Gets the URI of the XAML file currently being loaded.
+        /// </summary>
+        /// <remarks>
+        /// TODO: Making this internal for now as I'm not sure that this is the correct
+        /// thing to do, but its needed by <see cref="StyleInclude"/> to get the URL of
+        /// the currently loading XAML file, as we can't use the OmniXAML parsing context
+        /// there. Maybe we need a way to inject OmniXAML context into the objects its
+        /// constructing?
+        /// </remarks>
+        internal static Uri UriContext => s_uriStack.Count > 0 ? s_uriStack.Peek() : null;
+
+        /// <summary>
+        /// Loads the XAML into a Avalonia component.
+        /// </summary>
+        /// <param name="obj">The object to load the XAML into.</param>
+        public static void Load(object obj)
+        {
+            Contract.Requires<ArgumentNullException>(obj != null);
+
+            var loader = new AvaloniaXamlLoaderOmniXaml();
+            loader.Load(obj.GetType(), obj);
+        }
+
+        /// <summary>
+        /// Loads the XAML for a type.
+        /// </summary>
+        /// <param name="type">The type.</param>
+        /// <param name="rootInstance">
+        /// The optional instance into which the XAML should be loaded.
+        /// </param>
+        /// <returns>The loaded object.</returns>
+        public object Load(Type type, object rootInstance = null)
+        {
+            Contract.Requires<ArgumentNullException>(type != null);
+
+            // HACK: Currently Visual Studio is forcing us to change the extension of xaml files
+            // in certain situations, so we try to load .xaml and if that's not found we try .xaml.
+            // Ideally we'd be able to use .xaml everywhere
+            var assetLocator = AvaloniaLocator.Current.GetService<IAssetLoader>();
+
+            if (assetLocator == null)
+            {
+                throw new InvalidOperationException(
+                    "Could not create IAssetLoader : maybe Application.RegisterServices() wasn't called?");
+            }
+
+            foreach (var uri in GetUrisFor(type))
+            {
+                if (assetLocator.Exists(uri))
+                {
+                    using (var stream = assetLocator.Open(uri))
+                    {
+                        var initialize = rootInstance as ISupportInitialize;
+                        initialize?.BeginInit();
+                        return Load(stream, rootInstance, uri);
+                    }
+                }
+            }
+
+            throw new FileNotFoundException("Unable to find view for " + type.FullName);
+        }
+
+        /// <summary>
+        /// Loads XAML from a URI.
+        /// </summary>
+        /// <param name="uri">The URI of the XAML file.</param>
+        /// <param name="baseUri">
+        /// A base URI to use if <paramref name="uri"/> is relative.
+        /// </param>
+        /// <param name="rootInstance">
+        /// The optional instance into which the XAML should be loaded.
+        /// </param>
+        /// <returns>The loaded object.</returns>
+        public object Load(Uri uri, Uri baseUri = null, object rootInstance = null)
+        {
+            Contract.Requires<ArgumentNullException>(uri != null);
+
+            var assetLocator = AvaloniaLocator.Current.GetService<IAssetLoader>();
+
+            if (assetLocator == null)
+            {
+                throw new InvalidOperationException(
+                    "Could not create IAssetLoader : maybe Application.RegisterServices() wasn't called?");
+            }
+
+            using (var stream = assetLocator.Open(uri, baseUri))
+            {
+                return Load(stream, rootInstance, uri);
+            }
+        }
+
+        /// <summary>
+        /// Loads XAML from a string.
+        /// </summary>
+        /// <param name="xaml">The string containing the XAML.</param>
+        /// <param name="rootInstance">
+        /// The optional instance into which the XAML should be loaded.
+        /// </param>
+        /// <returns>The loaded object.</returns>
+        public object Load(string xaml, object rootInstance = null)
+        {
+            Contract.Requires<ArgumentNullException>(xaml != null);
+
+            using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(xaml)))
+            {
+                return Load(stream, rootInstance);
+            }
+        }
+
+        /// <summary>
+        /// Loads XAML from a stream.
+        /// </summary>
+        /// <param name="stream">The stream containing the XAML.</param>
+        /// <param name="rootInstance">
+        /// The optional instance into which the XAML should be loaded.
+        /// </param>
+        /// <param name="uri">The URI of the XAML</param>
+        /// <returns>The loaded object.</returns>
+        public object Load(Stream stream, object rootInstance = null, Uri uri = null)
+        {
+            try
+            {
+                if (uri != null)
+                {
+                    s_uriStack.Push(uri);
+                }
+
+                var result = base.Load(stream, new Settings
+                {
+                    RootInstance = rootInstance,
+                    InstanceLifeCycleListener = s_lifeCycleListener,
+                    ParsingContext = new Dictionary<string, object>
+                    {
+                        { "Uri", uri }
+                    }
+                });
+
+                var topLevel = result as TopLevel;
+
+                if (topLevel != null)
+                {
+                    DelayedBinding.ApplyBindings(topLevel);
+                }
+
+                return result;
+            }
+            finally
+            {
+                if (uri != null)
+                {
+                    s_uriStack.Pop();
+                }
+            }
+        }
+
+        private static AvaloniaParserFactory GetParserFactory()
+        {
+            if (s_parserFactory == null)
+            {
+                s_parserFactory = new AvaloniaParserFactory();
+            }
+
+            return s_parserFactory;
+        }
+
+        /// <summary>
+        /// Gets the URI for a type.
+        /// </summary>
+        /// <param name="type">The type.</param>
+        /// <returns>The URI.</returns>
+        private static IEnumerable<Uri> GetUrisFor(Type type)
+        {
+            var asm = type.GetTypeInfo().Assembly.GetName().Name;
+            var typeName = type.FullName;
+            yield return new Uri("resm:" + typeName + ".xaml?assembly=" + asm);
+            yield return new Uri("resm:" + typeName + ".paml?assembly=" + asm);
+
+        }
+    }
+#endif
+}

+ 219 - 0
src/Markup/Avalonia.Markup.Xaml/AvaloniaXamlLoaderPortableXaml.cs

@@ -0,0 +1,219 @@
+// Copyright (c) The Avalonia 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.IO;
+using System.Reflection;
+using System.Text;
+using Avalonia.Controls;
+using Avalonia.Markup.Xaml.Context;
+using Avalonia.Markup.Xaml.Data;
+using Avalonia.Markup.Xaml.PortableXaml;
+using Avalonia.Platform;
+using Portable.Xaml;
+
+namespace Avalonia.Markup.Xaml
+{
+    /// <summary>
+    /// Loads XAML for a avalonia application.
+    /// </summary>
+    public class AvaloniaXamlLoaderPortableXaml
+    {
+        internal static readonly AvaloniaXamlSchemaContext _context
+            = new AvaloniaXamlSchemaContext(new AvaloniaRuntimeTypeProvider());
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="AvaloniaXamlLoader"/> class.
+        /// </summary>
+        public AvaloniaXamlLoaderPortableXaml()
+        {
+        }
+
+        /// <summary>
+        /// Gets the URI of the XAML file currently being loaded.
+        /// </summary>
+        /// <remarks>
+        /// TODO: Making this internal for now as I'm not sure that this is the correct
+        /// thing to do, but its needed by <see cref="StyleInclude"/> to get the URL of
+        /// the currently loading XAML file, as we can't use the OmniXAML parsing context
+        /// there. Maybe we need a way to inject OmniXAML context into the objects its
+        /// constructing?
+        /// </remarks>
+        [Obsolete]
+        internal static Uri UriContext => s_uriStack.Count > 0 ? s_uriStack.Peek() : null;
+
+        private static Stack<Uri> s_uriStack = new Stack<Uri>();
+
+        /// <summary>
+        /// Loads the XAML into a Avalonia component.
+        /// </summary>
+        /// <param name="obj">The object to load the XAML into.</param>
+        public static void Load(object obj)
+        {
+            Contract.Requires<ArgumentNullException>(obj != null);
+
+            var loader = new AvaloniaXamlLoader();
+            loader.Load(obj.GetType(), obj);
+        }
+
+        /// <summary>
+        /// Loads the XAML for a type.
+        /// </summary>
+        /// <param name="type">The type.</param>
+        /// <param name="rootInstance">
+        /// The optional instance into which the XAML should be loaded.
+        /// </param>
+        /// <returns>The loaded object.</returns>
+        public object Load(Type type, object rootInstance = null)
+        {
+            Contract.Requires<ArgumentNullException>(type != null);
+
+            // HACK: Currently Visual Studio is forcing us to change the extension of xaml files
+            // in certain situations, so we try to load .xaml and if that's not found we try .xaml.
+            // Ideally we'd be able to use .xaml everywhere
+            var assetLocator = AvaloniaLocator.Current.GetService<IAssetLoader>();
+
+            if (assetLocator == null)
+            {
+                throw new InvalidOperationException(
+                    "Could not create IAssetLoader : maybe Application.RegisterServices() wasn't called?");
+            }
+
+            foreach (var uri in GetUrisFor(type))
+            {
+                if (assetLocator.Exists(uri))
+                {
+                    using (var stream = assetLocator.Open(uri))
+                    {
+                        var initialize = rootInstance as ISupportInitialize;
+                        initialize?.BeginInit();
+                        return Load(stream, type, rootInstance, uri);
+                    }
+                }
+            }
+
+            throw new FileNotFoundException("Unable to find view for " + type.FullName);
+        }
+
+        /// <summary>
+        /// Loads XAML from a URI.
+        /// </summary>
+        /// <param name="uri">The URI of the XAML file.</param>
+        /// <param name="baseUri">
+        /// A base URI to use if <paramref name="uri"/> is relative.
+        /// </param>
+        /// <param name="rootInstance">
+        /// The optional instance into which the XAML should be loaded.
+        /// </param>
+        /// <returns>The loaded object.</returns>
+        public object Load(Uri uri, Uri baseUri = null, object rootInstance = null)
+        {
+            Contract.Requires<ArgumentNullException>(uri != null);
+
+            var assetLocator = AvaloniaLocator.Current.GetService<IAssetLoader>();
+
+            if (assetLocator == null)
+            {
+                throw new InvalidOperationException(
+                    "Could not create IAssetLoader : maybe Application.RegisterServices() wasn't called?");
+            }
+
+            using (var stream = assetLocator.Open(uri, baseUri))
+            {
+                return Load(stream, null, rootInstance, uri);
+            }
+        }
+
+        /// <summary>
+        /// Loads XAML from a string.
+        /// </summary>
+        /// <param name="xaml">The string containing the XAML.</param>
+        /// <param name="rootInstance">
+        /// The optional instance into which the XAML should be loaded.
+        /// </param>
+        /// <returns>The loaded object.</returns>
+        public object Load(string xaml, Type type = null, object rootInstance = null)
+        {
+            Contract.Requires<ArgumentNullException>(xaml != null);
+
+            using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(xaml)))
+            {
+                return Load(stream, type, rootInstance);
+            }
+        }
+
+        /// <summary>
+        /// Loads XAML from a stream.
+        /// </summary>
+        /// <param name="stream">The stream containing the XAML.</param>
+        /// <param name="rootInstance">
+        /// The optional instance into which the XAML should be loaded.
+        /// </param>
+        /// <param name="uri">The URI of the XAML</param>
+        /// <returns>The loaded object.</returns>
+        public object Load(Stream stream, Type type = null, object rootInstance = null, Uri uri = null)
+        {
+            try
+            {
+                if (uri != null)
+                {
+                    s_uriStack.Push(uri);
+                }
+
+                var readerSettings = new XamlXmlReaderSettings();
+
+                if (rootInstance != null && type == null)
+                {
+                    type = rootInstance.GetType();
+                }
+
+                if (type != null)
+                {
+                    readerSettings.LocalAssembly = type.GetTypeInfo().Assembly;
+                }
+
+                var reader = new XamlXmlReader(stream, _context, readerSettings);
+                object result = Load(reader, rootInstance);
+
+                var topLevel = result as TopLevel;
+
+                if (topLevel != null)
+                {
+                    DelayedBinding.ApplyBindings(topLevel);
+                }
+
+                return result;
+            }
+            finally
+            {
+                if (uri != null)
+                {
+                    s_uriStack.Pop();
+                }
+            }
+        }
+
+        internal static object Load(XamlXmlReader reader, object instance)
+        {
+            var writer = AvaloniaXamlObjectWriter.Create(_context, instance);
+
+            XamlServices.Transform(reader, writer);
+
+            return writer.Result;
+        }
+
+        /// <summary>
+        /// Gets the URI for a type.
+        /// </summary>
+        /// <param name="type">The type.</param>
+        /// <returns>The URI.</returns>
+        private static IEnumerable<Uri> GetUrisFor(Type type)
+        {
+            var asm = type.GetTypeInfo().Assembly.GetName().Name;
+            var typeName = type.FullName;
+            yield return new Uri("resm:" + typeName + ".xaml?assembly=" + asm);
+            yield return new Uri("resm:" + typeName + ".paml?assembly=" + asm);
+        }
+    }
+}

+ 2 - 0
src/Markup/Avalonia.Markup.Xaml/Context/AvaloniaObjectAssembler.cs

@@ -12,6 +12,7 @@ using System.Collections.ObjectModel;
 
 namespace Avalonia.Markup.Xaml.Context
 {
+#if OMNIXAML
     public class AvaloniaObjectAssembler : IObjectAssembler
     {
         private readonly TemplateHostingObjectAssembler objectAssembler;
@@ -76,4 +77,5 @@ namespace Avalonia.Markup.Xaml.Context
             return dict;
         }
     }
+#endif
 }

+ 2 - 0
src/Markup/Avalonia.Markup.Xaml/Context/AvaloniaParserFactory.cs

@@ -8,6 +8,7 @@ using OmniXaml.Parsers.ProtoParser;
 
 namespace Avalonia.Markup.Xaml.Context
 {
+#if OMNIXAML
     public class AvaloniaParserFactory : IParserFactory
     {
         private readonly IRuntimeTypeSource runtimeTypeSource;
@@ -38,4 +39,5 @@ namespace Avalonia.Markup.Xaml.Context
             return new XmlParser(phaseParserKit);
         }
     }
+#endif
 }

+ 1 - 1
src/Markup/Avalonia.Markup.Xaml/Context/AvaloniaTypeFeatureProvider.cs

@@ -171,7 +171,7 @@ namespace Avalonia.Markup.Xaml.Context
             RegisterTypeConverter(typeof(SolidColorBrush), new BrushTypeConverter());
             RegisterTypeConverter(typeof(Thickness), new ThicknessTypeConverter());
             RegisterTypeConverter(typeof(TimeSpan), new TimeSpanTypeConverter());
-            RegisterTypeConverter(typeof(Uri), new UriTypeConverter());
+            RegisterTypeConverter(typeof(Uri), new Converters.UriTypeConverter());
             RegisterTypeConverter(typeof(Cursor), new CursorTypeConverter());
             RegisterTypeConverter(typeof(WindowIcon), new IconTypeConverter());
             RegisterTypeConverter(typeof(FontWeight), new FontWeightConverter());

+ 69 - 0
src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaMemberAttributeProvider.cs

@@ -0,0 +1,69 @@
+using System;
+using System.Linq;
+using System.Reflection;
+using Avalonia.Markup.Xaml.Templates;
+using Portable.Xaml.ComponentModel;
+using avm = Avalonia.Metadata;
+using pm = Portable.Xaml.Markup;
+
+namespace Avalonia.Markup.Xaml.PortableXaml
+{
+    public class AvaloniaMemberAttributeProvider : ICustomAttributeProvider
+    {
+        public AvaloniaMemberAttributeProvider(MemberInfo info)
+        {
+            _info = info;
+        }
+
+        public object[] GetCustomAttributes(bool inherit)
+        {
+            throw new NotImplementedException();
+        }
+
+        public object[] GetCustomAttributes(Type attributeType, bool inherit)
+        {
+            object[] result = null;
+
+            if (attributeType == typeof(pm.XamlDeferLoadAttribute))
+            {
+                var attr = GetXamlDeferLoadAttribute(inherit);
+
+                if (attr != null)
+                {
+                    result = new object[] { attr };
+                }
+            }
+
+            if (result == null || result.Length == 0)
+            {
+                var attr = _info.GetCustomAttributes(attributeType, inherit);
+                return (attr as object[]) ?? attr.ToArray();
+            }
+            else
+            {
+                return result;
+            }
+        }
+
+        public bool IsDefined(Type attributeType, bool inherit)
+        {
+            throw new NotImplementedException();
+        }
+
+        private readonly MemberInfo _info;
+
+        private Attribute GetXamlDeferLoadAttribute(bool inherit)
+        {
+            var result = _info.GetCustomAttributes(typeof(avm.TemplateContentAttribute), inherit)
+                                            .Cast<avm.TemplateContentAttribute>()
+                                            .FirstOrDefault();
+
+            if (result == null)
+            {
+                return null;
+            }
+
+            return new pm.XamlDeferLoadAttribute(typeof(TemplateLoader), typeof(TemplateContent));
+        }
+    }
+}

+ 56 - 0
src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaNameScope.cs

@@ -0,0 +1,56 @@
+using System.Collections.Generic;
+using Avalonia.Controls;
+
+namespace Avalonia.Markup.Xaml.PortableXaml
+{
+    internal class AvaloniaNameScope : Portable.Xaml.Markup.INameScope
+    {
+        public object Instance { get; set; }
+
+        private Dictionary<string, object> _names = new Dictionary<string, object>();
+
+        public object FindName(string name)
+        {
+            object result;
+            if (_names.TryGetValue(name, out result))
+                return result;
+            return null;
+        }
+
+        public void RegisterName(string name, object scopedElement)
+        {
+            if (scopedElement != null)
+                _names.Add(name, scopedElement);
+
+            //TODO: ???
+            //var control = scopedElement as Control;
+
+            //if (control != null)
+            //{
+            //    var nameScope = (Instance as INameScope) ?? control.FindNameScope();
+
+            //    if (nameScope != null)
+            //    {
+            //        nameScope.Register(name, scopedElement);
+            //    }
+            //}
+        }
+
+        public void UnregisterName(string name)
+        {
+        }
+
+        public void RegisterOnNameScope(object target)
+        {
+            var nameScope = target as INameScope;
+
+            if (nameScope != null)
+            {
+                foreach (var v in _names)
+                {
+                    nameScope.Register(v.Key, v.Value);
+                }
+            }
+        }
+    }
+}

+ 147 - 0
src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaRuntimeTypeProvider.cs

@@ -0,0 +1,147 @@
+// Copyright (c) The Avalonia 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 Avalonia.Controls;
+using Avalonia.Markup.Xaml.Templates;
+using Avalonia.Media;
+using Avalonia.Metadata;
+using Avalonia.Platform;
+using Avalonia.Styling;
+
+namespace Avalonia.Markup.Xaml.Context
+{
+    using ClrNamespaceInfo = Tuple<string, Assembly>;
+
+    public interface IRuntimeTypeProvider
+    {
+        Type FindType(string xamlNamespace, string name, Type[] genArgs);
+
+        IEnumerable<Assembly> ReferencedAssemblies { get; }
+    }
+
+    public class AvaloniaRuntimeTypeProvider : IRuntimeTypeProvider
+    {
+        private const string ClrNamespace = "clr-namespace:";
+        // private const string AvaloniaNs = "https://github.com/avaloniaui";
+
+        private static readonly IEnumerable<Assembly> ForcedAssemblies = new[]
+        {
+            typeof(AvaloniaObject).GetTypeInfo().Assembly,
+            typeof(Control).GetTypeInfo().Assembly,
+            typeof(Style).GetTypeInfo().Assembly,
+            typeof(DataTemplate).GetTypeInfo().Assembly,
+            typeof(SolidColorBrush).GetTypeInfo().Assembly,
+            typeof(IValueConverter).GetTypeInfo().Assembly,
+        };
+
+        private Dictionary<string, HashSet<ClrNamespaceInfo>> _namespaces = new Dictionary<string, HashSet<ClrNamespaceInfo>>();
+
+        private List<Assembly> _scanned = new List<Assembly>();
+
+        public IEnumerable<Assembly> ReferencedAssemblies => _scanned;
+
+        public AvaloniaRuntimeTypeProvider()
+        {
+            ScanAssemblies(ForcedAssemblies);
+            ScanNewAssemblies();
+        }
+
+        private static bool IsClrNamespace(string ns)
+        {
+            return ns.StartsWith(ClrNamespace);
+        }
+
+        private static Assembly GetAssembly(string assemblyName)
+        {
+            return Assembly.Load(new AssemblyName(assemblyName));
+        }
+
+        private void ScanAssemblies(IEnumerable<Assembly> assemblies)
+        {
+            foreach (var assembly in assemblies)
+            {
+                var namespaces = assembly.GetCustomAttributes<XmlnsDefinitionAttribute>()
+                    .Select(x => new { x.XmlNamespace, x.ClrNamespace })
+                    .GroupBy(x => x.XmlNamespace);
+
+                foreach (var nsa in namespaces)
+                {
+                    HashSet<ClrNamespaceInfo> reg;
+
+                    if (!_namespaces.TryGetValue(nsa.Key, out reg))
+                    {
+                        _namespaces[nsa.Key] = reg = new HashSet<Tuple<string, Assembly>>();
+                    }
+
+                    foreach (var child in nsa)
+                    {
+                        reg.Add(new ClrNamespaceInfo(child.ClrNamespace, assembly));
+                    }
+                }
+
+                _scanned.Add(assembly);
+            }
+        }
+
+        private void ScanNewAssemblies()
+        {
+            IEnumerable<Assembly> assemblies = AvaloniaLocator.Current
+                .GetService<IRuntimePlatform>()
+                ?.GetLoadedAssemblies();
+
+            if (assemblies != null)
+            {
+                assemblies = assemblies.Except(_scanned);
+                ScanAssemblies(assemblies);
+            }
+        }
+
+        private Dictionary<string, Type> _typeCache = new Dictionary<string, Type>();
+
+        public Type FindType(string xamlNamespace, string name, Type[] genArgs)
+        {
+            if (IsClrNamespace(xamlNamespace))
+            {
+                //we need to handle only xaml url namespaces for avalonia,
+                //the other namespaces are handled well in portable.xaml
+                return null;
+            }
+
+            string key = $"{xamlNamespace}:{name}";
+
+            Type type;
+
+            if (_typeCache.TryGetValue(key, out type))
+            {
+                return type;
+            }
+
+            HashSet<ClrNamespaceInfo> reg;
+
+            if (!_namespaces.TryGetValue(xamlNamespace, out reg))
+            {
+                return null;
+            }
+
+            if (genArgs != null)
+                name += "`" + genArgs.Length;
+
+            foreach (var ns in reg)
+            {
+                var n = ns.Item1 + "." + name;
+                var t = ns.Item2.GetType(n);
+                if (t != null)
+                {
+                    _typeCache[key] = t;
+                    return t;
+                }
+            }
+
+            return null;
+        }
+    }
+}

+ 91 - 0
src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaTypeAttributeProvider.cs

@@ -0,0 +1,91 @@
+// 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.Linq;
+using System.Reflection;
+using Avalonia.Metadata;
+using Portable.Xaml.ComponentModel;
+using pm = Portable.Xaml.Markup;
+
+namespace Avalonia.Markup.Xaml.PortableXaml
+{
+    internal class AvaloniaTypeAttributeProvider : ICustomAttributeProvider
+    {
+        public AvaloniaTypeAttributeProvider(Type type)
+        {
+            _type = type;
+        }
+
+        public object[] GetCustomAttributes(bool inherit)
+        {
+            throw new NotImplementedException();
+        }
+
+        public object[] GetCustomAttributes(Type attributeType, bool inherit)
+        {
+            if (attributeType == typeof(pm.ContentPropertyAttribute))
+            {
+                var cp = GetContentPropertyAttribute(inherit);
+
+                if (cp != null)
+                {
+                    return new object[] { cp };
+                }
+            }
+            else if (attributeType == typeof(pm.RuntimeNamePropertyAttribute))
+            {
+                if (_namedType.IsAssignableFrom(_type.GetTypeInfo()))
+                {
+                    return new object[]
+                         {
+                             new pm.RuntimeNamePropertyAttribute(nameof(INamed.Name))
+                         };
+                }
+            }
+
+            var attr = _type.GetTypeInfo().GetCustomAttributes(attributeType, inherit);
+            return (attr as object[]) ?? attr.ToArray();
+        }
+
+        public bool IsDefined(Type attributeType, bool inherit)
+        {
+            throw new NotImplementedException();
+        }
+
+        private readonly TypeInfo _namedType = typeof(INamed).GetTypeInfo();
+
+        private readonly Type _type;
+
+        private Attribute GetContentPropertyAttribute(bool inherit)
+        {
+            var type = _type;
+
+            while (type != null)
+            {
+                var properties = type.GetTypeInfo().DeclaredProperties
+                    .Where(x => x.GetCustomAttribute<ContentAttribute>() != null);
+                string result = null;
+
+                foreach (var property in properties)
+                {
+                    if (result != null)
+                    {
+                        throw new Exception($"Content property defined more than once on {type}.");
+                    }
+
+                    result = property.Name;
+                }
+
+                if (result != null)
+                {
+                    return new pm.ContentPropertyAttribute(result);
+                }
+
+                type = inherit ? type.GetTypeInfo().BaseType : null;
+            }
+
+            return null;
+        }
+    }
+}

+ 101 - 0
src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaXamlObjectWriter.cs

@@ -0,0 +1,101 @@
+using Portable.Xaml;
+
+namespace Avalonia.Markup.Xaml.PortableXaml
+{
+    public class AvaloniaXamlObjectWriter : XamlObjectWriter
+    {
+        public static AvaloniaXamlObjectWriter Create(XamlSchemaContext schemaContext, object instance)
+        {
+            var writerSettings = new XamlObjectWriterSettings();
+            var nameScope = new AvaloniaNameScope { Instance = instance };
+            writerSettings.ExternalNameScope = nameScope;
+            writerSettings.RegisterNamesOnExternalNamescope = true;
+            writerSettings.RootObjectInstance = instance;
+
+            return new AvaloniaXamlObjectWriter(schemaContext, writerSettings, nameScope);
+        }
+
+        private AvaloniaXamlObjectWriter(
+            XamlSchemaContext schemaContext,
+            XamlObjectWriterSettings settings,
+            AvaloniaNameScope nameScope
+            )
+            : base(schemaContext, settings)
+        {
+            _nameScope = nameScope;
+        }
+
+        protected override void OnAfterBeginInit(object value)
+        {
+            base.OnAfterBeginInit(value);
+        }
+
+        protected override void OnAfterEndInit(object value)
+        {
+            base.OnAfterEndInit(value);
+        }
+
+        protected override void OnAfterProperties(object value)
+        {
+            base.OnAfterProperties(value);
+
+            //AfterEndInit is not called as it supports only
+            //Portable.Xaml.ComponentModel.ISupportInitialize
+            //and we have Avalonia.ISupportInitialize so we need some hacks
+            _endEditValue = value;
+        }
+
+        protected override void OnBeforeProperties(object value)
+        {
+            //OnAfterBeginInit is not called as it supports only
+            //Portable.Xaml.ComponentModel.ISupportInitialize
+            //and we have Avalonia.ISupportInitialize so we need some hacks
+            HandleBeginInit(value);
+
+            base.OnBeforeProperties(value);
+        }
+
+        public override void WriteEndObject()
+        {
+            base.WriteEndObject();
+
+            //AfterEndInit is not called as it supports only
+            //Portable.Xaml.ComponentModel.ISupportInitialize
+            //and we have Avalonia.ISupportInitialize so we need some hacks
+            HandleEndEdit(_endEditValue);
+            _endEditValue = null;
+        }
+
+        private object _endEditValue;
+
+        private AvaloniaNameScope _nameScope;
+
+        private void HandleBeginInit(object value)
+        {
+            (value as Avalonia.ISupportInitialize)?.BeginInit();
+        }
+
+        private void HandleEndEdit(object value)
+        {
+            (value as Avalonia.ISupportInitialize)?.EndInit();
+        }
+
+        private void HandleFinished()
+        {
+            if(_nameScope != null &&  Result != null)
+            {
+                _nameScope.RegisterOnNameScope(Result);
+            }
+        }
+
+        protected override void Dispose(bool disposing)
+        {
+            if (disposing)
+            {
+                HandleFinished();
+            }
+
+            base.Dispose(disposing);
+        }
+    }
+}

+ 70 - 0
src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaXamlSchemaContext.cs

@@ -0,0 +1,70 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using Avalonia.Markup.Xaml.Context;
+using Portable.Xaml;
+using Portable.Xaml.ComponentModel;
+
+namespace Avalonia.Markup.Xaml.PortableXaml
+{
+    internal class AvaloniaXamlSchemaContext : XamlSchemaContext
+    {
+        public AvaloniaXamlSchemaContext(IRuntimeTypeProvider typeProvider)
+            : base(typeProvider.ReferencedAssemblies)
+        {
+            _avaloniaTypeProvider = typeProvider;
+        }
+
+        private IRuntimeTypeProvider _avaloniaTypeProvider;
+
+        protected override XamlType GetXamlType(string xamlNamespace, string name, params XamlType[] typeArguments)
+        {
+            XamlType type = null;
+            try
+            {
+                type = ResolveXamlTypeName(xamlNamespace, name, typeArguments, false);
+
+                if (type == null)
+                {
+                    type = base.GetXamlType(xamlNamespace, name, typeArguments);
+                }
+            }
+            catch(Exception e)
+            {
+                //TODO: log or wrap exception
+                throw e;
+            }
+            return type;
+        }
+
+        private XamlType ResolveXamlTypeName(string xmlNamespace, string xmlLocalName, XamlType[] typeArguments, bool required)
+        {
+            Type[] genArgs = null;
+            if (typeArguments != null && typeArguments.Any())
+            {
+                genArgs = typeArguments.Select(t => t?.UnderlyingType).ToArray();
+
+                if (genArgs.Any(t => t == null))
+                {
+                    return null;
+                }
+            }
+
+            Type type = _avaloniaTypeProvider.FindType(xmlNamespace, xmlLocalName, genArgs);
+
+            if (type == null)
+            {
+                return null;
+            }
+
+            return GetXamlType(type);
+        }
+
+        protected override ICustomAttributeProvider GetCustomAttributeProvider(Type type)
+                                    => new AvaloniaTypeAttributeProvider(type);
+
+        protected override ICustomAttributeProvider GetCustomAttributeProvider(MemberInfo member)
+                                    => new AvaloniaMemberAttributeProvider(member);
+    }
+}

+ 7 - 3
src/Markup/Avalonia.Markup.Xaml/Templates/DataTemplate.cs

@@ -13,10 +13,14 @@ namespace Avalonia.Markup.Xaml.Templates
     {
         public Type DataType { get; set; }
 
+        //we need content to be object otherwise portable.xaml is crashing
         [Content]
-        public TemplateContent Content { get; set; }
+        [TemplateContent]
+        public object Content { get; set; }
 
-        public bool SupportsRecycling => true;
+        private TemplateContent TemplateContent => (TemplateContent)Content;
+
+        public bool SupportsRecycling { get; set; }
 
         public bool Match(object data)
         {
@@ -30,6 +34,6 @@ namespace Avalonia.Markup.Xaml.Templates
             }
         }
 
-        public IControl Build(object data) => Content.Load();
+        public IControl Build(object data) => TemplateContent.Load();
     }
 }

+ 29 - 2
src/Markup/Avalonia.Markup.Xaml/Templates/TemplateContent.cs

@@ -2,13 +2,38 @@
 // Licensed under the MIT license. See licence.md file in the project root for full license information.
 
 using System.Collections.Generic;
-using OmniXaml;
-using OmniXaml.ObjectAssembler;
 using Avalonia.Controls;
 using Avalonia.Markup.Xaml.Context;
 
 namespace Avalonia.Markup.Xaml.Templates
 {
+#if !OMNIXAML
+    using Portable.Xaml;
+
+    public class TemplateContent
+    {
+        public TemplateContent()
+        {
+        }
+
+        public TemplateContent(XamlReader reader)
+        {
+            List = new XamlNodeList(reader.SchemaContext);
+            XamlServices.Transform(reader, List.Writer);
+        }
+
+        public XamlNodeList List { get; set; }
+
+        public IControl Load()
+        {
+            return (IControl)XamlServices.Load(List.GetReader());
+        }
+    }
+#else
+
+    using OmniXaml;
+    using OmniXaml.ObjectAssembler;
+
     public class TemplateContent
     {
         private readonly IEnumerable<Instruction> nodes;
@@ -34,4 +59,6 @@ namespace Avalonia.Markup.Xaml.Templates
             return (Control)assembler.Result;
         }
     }
+
+#endif
 }

+ 22 - 1
src/Markup/Avalonia.Markup.Xaml/Templates/TemplateLoader.cs

@@ -2,10 +2,29 @@
 // Licensed under the MIT license. See licence.md file in the project root for full license information.
 
 using System.Collections.Generic;
-using OmniXaml;
 
 namespace Avalonia.Markup.Xaml.Templates
 {
+#if !OMNIXAML
+    using Portable.Xaml;
+    using System;
+
+    public class TemplateLoader : XamlDeferringLoader
+    {
+        public override object Load(XamlReader xamlReader, IServiceProvider serviceProvider)
+        {
+            return new TemplateContent(xamlReader);
+        }
+
+        public override XamlReader Save(object value, IServiceProvider serviceProvider)
+        {
+            return ((TemplateContent)value).List.GetReader();
+        }
+    }
+#else
+
+    using OmniXaml;
+
     public class TemplateLoader : IDeferredLoader
     {
         public object Load(IEnumerable<Instruction> nodes, IRuntimeTypeSource runtimeTypeSource)
@@ -13,4 +32,6 @@ namespace Avalonia.Markup.Xaml.Templates
             return new TemplateContent(nodes, runtimeTypeSource);
         }
     }
+
+#endif
 }

+ 1 - 0
src/Markup/Avalonia.Markup.Xaml/packages.config

@@ -1,5 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <packages>
+  <package id="Portable.Xaml" version="0.15.0" targetFramework="portable45-net45+win8" />
   <package id="Sprache" version="2.1.0" targetFramework="portable45-net45+win8" />
   <package id="System.Globalization" version="4.0.11" targetFramework="portable45-net45+win8" />
   <package id="System.Linq" version="4.1.0" targetFramework="portable45-net45+win8" />

+ 11 - 0
src/Markup/Avalonia.Markup/Avalonia.Markup.csproj

@@ -114,6 +114,14 @@
     </ProjectReference>
   </ItemGroup>
   <ItemGroup>
+    <Reference Include="System.ComponentModel.Primitives, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
+      <HintPath>..\..\..\packages\System.ComponentModel.Primitives.4.3.0\lib\netstandard1.0\System.ComponentModel.Primitives.dll</HintPath>
+      <Private>True</Private>
+    </Reference>
+    <Reference Include="System.ComponentModel.TypeConverter, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
+      <HintPath>..\..\..\packages\System.ComponentModel.TypeConverter.4.3.0\lib\netstandard1.0\System.ComponentModel.TypeConverter.dll</HintPath>
+      <Private>True</Private>
+    </Reference>
     <Reference Include="System.Reactive.Core, Version=3.0.0.0, Culture=neutral, PublicKeyToken=94bc3704cddfc263, processorArchitecture=MSIL">
       <HintPath>..\..\..\packages\System.Reactive.Core.3.0.0\lib\netstandard1.1\System.Reactive.Core.dll</HintPath>
       <Private>True</Private>
@@ -134,6 +142,9 @@
   <ItemGroup>
     <None Include="packages.config" />
   </ItemGroup>
+  <ItemGroup>
+    <Folder Include="Common\" />
+  </ItemGroup>
   <Import Project="$(MSBuildExtensionsPath32)\Microsoft\Portable\$(TargetFrameworkVersion)\Microsoft.Portable.CSharp.targets" />
   <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
        Other similar extension points exist, see Microsoft.Common.targets.

+ 12 - 0
src/Markup/Avalonia.Markup/packages.config

@@ -1,9 +1,21 @@
 <?xml version="1.0" encoding="utf-8"?>
 <packages>
+  <package id="System.Collections" version="4.3.0" targetFramework="portable45-net45+win8" />
+  <package id="System.ComponentModel" version="4.3.0" targetFramework="portable45-net45+win8" />
   <package id="System.ComponentModel.Annotations" version="4.1.0" targetFramework="portable45-net45+win8" />
+  <package id="System.ComponentModel.Primitives" version="4.3.0" targetFramework="portable45-net45+win8" />
+  <package id="System.ComponentModel.TypeConverter" version="4.3.0" targetFramework="portable45-net45+win8" />
+  <package id="System.Globalization" version="4.3.0" targetFramework="portable45-net45+win8" />
   <package id="System.Reactive" version="3.0.0" targetFramework="portable45-net45+win8" />
   <package id="System.Reactive.Core" version="3.0.0" targetFramework="portable45-net45+win8" />
   <package id="System.Reactive.Interfaces" version="3.0.0" targetFramework="portable45-net45+win8" />
   <package id="System.Reactive.Linq" version="3.0.0" targetFramework="portable45-net45+win8" />
   <package id="System.Reactive.PlatformServices" version="3.0.0" targetFramework="portable45-net45+win8" />
+  <package id="System.Reflection" version="4.3.0" targetFramework="portable45-net45+win8" />
+  <package id="System.Reflection.Extensions" version="4.3.0" targetFramework="portable45-net45+win8" />
+  <package id="System.Reflection.Primitives" version="4.3.0" targetFramework="portable45-net45+win8" />
+  <package id="System.Resources.ResourceManager" version="4.3.0" targetFramework="portable45-net45+win8" />
+  <package id="System.Runtime" version="4.3.0" targetFramework="portable45-net45+win8" />
+  <package id="System.Runtime.Extensions" version="4.3.0" targetFramework="portable45-net45+win8" />
+  <package id="System.Threading" version="4.3.0" targetFramework="portable45-net45+win8" />
 </packages>