Ver Fonte

Merge pull request #2322 from AvaloniaUI/xamlil

XAML to IL Compilation
danwalmsley há 6 anos atrás
pai
commit
9910610573
99 ficheiros alterados com 3434 adições e 164 exclusões
  1. 3 0
      .gitmodules
  2. 3 3
      build/EmbedXaml.props
  3. 5 0
      build/SampleApp.props
  4. 3 3
      dirs.proj
  5. 37 2
      packages/Avalonia/AvaloniaBuildTasks.targets
  6. 1 0
      samples/ControlCatalog.NetCore/ControlCatalog.NetCore.csproj
  7. 1 1
      samples/ControlCatalog/App.xaml
  8. 15 8
      samples/ControlCatalog/MainView.xaml.cs
  9. 1 0
      samples/ControlCatalog/MainWindow.xaml
  10. 0 9
      samples/ControlCatalog/Pages/ButtonPage.xaml.cs
  11. 1 1
      samples/ControlCatalog/Pages/ButtonSpinnerPage.xaml.cs
  12. 1 1
      samples/ControlCatalog/SideBar.xaml
  13. 11 10
      src/Avalonia.Base/AvaloniaProperty.cs
  14. 4 1
      src/Avalonia.Base/Data/Core/ExpressionParseException.cs
  15. 10 0
      src/Avalonia.Base/Metadata/UsableDuringInitializationAttribute.cs
  16. 10 0
      src/Avalonia.Base/Platform/IAssetLoader.cs
  17. 30 0
      src/Avalonia.Base/Utilities/AvaloniaResourcesIndex.cs
  18. 4 1
      src/Avalonia.Base/Utilities/CharacterReader.cs
  19. 4 1
      src/Avalonia.Base/Utilities/IdentifierParser.cs
  20. 57 5
      src/Avalonia.Build.Tasks/Avalonia.Build.Tasks.csproj
  21. 73 0
      src/Avalonia.Build.Tasks/CompileAvaloniaXamlTask.cs
  22. 2 1
      src/Avalonia.Build.Tasks/Extensions.cs
  23. 61 0
      src/Avalonia.Build.Tasks/Program.cs
  24. 73 0
      src/Avalonia.Build.Tasks/SpanCompat.cs
  25. 149 0
      src/Avalonia.Build.Tasks/XamlCompilerTaskExecutor.Helpers.cs
  26. 357 0
      src/Avalonia.Build.Tasks/XamlCompilerTaskExecutor.cs
  27. 5 1
      src/Avalonia.Controls.DataGrid/Avalonia.Controls.DataGrid.csproj
  28. 1 0
      src/Avalonia.Controls.DataGrid/DataGridBoundColumn.cs
  29. 5 3
      src/Avalonia.DesignerSupport/Remote/RemoteDesignerEntryPoint.cs
  30. 1 0
      src/Avalonia.Diagnostics/Avalonia.Diagnostics.csproj
  31. 3 1
      src/Avalonia.Diagnostics/DevTools.xaml
  32. 6 0
      src/Avalonia.Diagnostics/DevTools.xaml.cs
  33. 2 1
      src/Avalonia.Diagnostics/Views/EventsView.xaml
  34. 3 1
      src/Avalonia.Diagnostics/Views/TreePageView.xaml
  35. 2 1
      src/Avalonia.Styling/Controls/NameScopeExtensions.cs
  36. 11 0
      src/Avalonia.Styling/Styling/Selectors.cs
  37. 1 1
      src/Avalonia.Themes.Default/Accents/BaseDark.xaml
  38. 1 1
      src/Avalonia.Themes.Default/Accents/BaseLight.xaml
  39. 5 6
      src/Avalonia.Themes.Default/Avalonia.Themes.Default.csproj
  40. 3 6
      src/Avalonia.Themes.Default/DatePicker.xaml
  41. 3 1
      src/Avalonia.Themes.Default/DefaultTheme.xaml
  42. 0 7
      src/Avalonia.Themes.Default/DefaultTheme.xaml.cs
  43. 1 1
      src/Avalonia.Themes.Default/MenuItem.xaml
  44. 2 0
      src/Avalonia.Visuals/Visual.cs
  45. 31 1
      src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj
  46. 1 0
      src/Markup/Avalonia.Markup.Xaml/AvaloniaTypeConverters.cs
  47. 24 11
      src/Markup/Avalonia.Markup.Xaml/AvaloniaXamlLoader.cs
  48. 2 2
      src/Markup/Avalonia.Markup.Xaml/Converters/AvaloniaPropertyTypeConverter.cs
  49. 4 3
      src/Markup/Avalonia.Markup.Xaml/Converters/AvaloniaUriTypeConverter.cs
  50. 2 2
      src/Markup/Avalonia.Markup.Xaml/Converters/BitmapTypeConverter.cs
  51. 1 1
      src/Markup/Avalonia.Markup.Xaml/Converters/FontFamilyTypeConverter.cs
  52. 1 1
      src/Markup/Avalonia.Markup.Xaml/Converters/IconTypeConverter.cs
  53. 61 0
      src/Markup/Avalonia.Markup.Xaml/Extensions.cs
  54. 8 3
      src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/BindingExtension.cs
  55. 5 15
      src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/DynamicResourceExtension.cs
  56. 6 1
      src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/ResourceInclude.cs
  57. 15 19
      src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/StaticResourceExtension.cs
  58. 4 4
      src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/StyleIncludeExtension.cs
  59. 2 2
      src/Markup/Avalonia.Markup.Xaml/PortableXaml/TypeDescriptorExtensions.cs
  60. 5 0
      src/Markup/Avalonia.Markup.Xaml/Styling/StyleInclude.cs
  61. 6 1
      src/Markup/Avalonia.Markup.Xaml/Templates/TemplateContent.cs
  62. 276 0
      src/Markup/Avalonia.Markup.Xaml/XamlIl/AvaloniaXamlIlRuntimeCompiler.cs
  63. 124 0
      src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/AvaloniaXamlIlCompiler.cs
  64. 176 0
      src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/AvaloniaXamlIlLanguage.cs
  65. 94 0
      src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AddNameScopeRegistration.cs
  66. 20 0
      src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaBindingExtensionHackTransformer.cs
  67. 24 0
      src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlAvaloniaPropertyResolver.cs
  68. 47 0
      src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlConstructorServiceProviderTransformer.cs
  69. 71 0
      src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlControlTemplateTargetTypeMetadataTransformer.cs
  70. 63 0
      src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlDesignPropertiesTransformer.cs
  71. 17 0
      src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlMetadataRemover.cs
  72. 338 0
      src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlSelectorTransformer.cs
  73. 108 0
      src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlSetterTransformer.cs
  74. 193 0
      src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlTransformInstanceAttachedProperties.cs
  75. 28 0
      src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlTransitionsTypeMetadataTransformer.cs
  76. 53 0
      src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlWellKnownTypes.cs
  77. 27 0
      src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/IgnoredDirectivesTransformer.cs
  78. 36 0
      src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/XNameTransformer.cs
  79. 186 0
      src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/XamlIlAvaloniaPropertyHelper.cs
  80. 9 0
      src/Markup/Avalonia.Markup.Xaml/XamlIl/Runtime/IAvaloniaXamlIlParentStackProvider.cs
  81. 15 0
      src/Markup/Avalonia.Markup.Xaml/XamlIl/Runtime/IAvaloniaXamlIlXmlNamespaceInfoProviderV1.cs
  82. 148 0
      src/Markup/Avalonia.Markup.Xaml/XamlIl/Runtime/XamlIlRuntimeHelpers.cs
  83. 1 0
      src/Markup/Avalonia.Markup.Xaml/XamlIl/xamlil.github
  84. 1 1
      src/Markup/Avalonia.Markup/Data/MultiBinding.cs
  85. 2 0
      src/Markup/Avalonia.Markup/Data/TemplateBinding.cs
  86. 1 1
      src/Markup/Avalonia.Markup/Markup/Parsers/SelectorGrammar.cs
  87. 7 0
      src/Shared/PlatformSupport/AssetLoader.cs
  88. 2 5
      tests/Avalonia.Markup.Xaml.UnitTests/Avalonia.Markup.Xaml.UnitTests.csproj
  89. 1 1
      tests/Avalonia.Markup.Xaml.UnitTests/StyleTests.cs
  90. 18 4
      tests/Avalonia.Markup.Xaml.UnitTests/Xaml/BasicTests.cs
  91. 1 1
      tests/Avalonia.Markup.Xaml.UnitTests/Xaml/DataTemplateTests.cs
  92. 7 3
      tests/Avalonia.Markup.Xaml.UnitTests/Xaml/EventTests.cs
  93. 3 2
      tests/Avalonia.Markup.Xaml.UnitTests/Xaml/Style1.xaml
  94. 3 2
      tests/Avalonia.Markup.Xaml.UnitTests/Xaml/Style2.xaml
  95. 6 0
      tests/Avalonia.Markup.Xaml.UnitTests/Xaml/XamlIlClassWithPrecompiledXaml.xaml
  96. 146 0
      tests/Avalonia.Markup.Xaml.UnitTests/Xaml/XamlIlTests.cs
  97. 23 0
      tests/Avalonia.Markup.Xaml.UnitTests/Xaml/XamlTestHelpers.cs
  98. 5 0
      tests/Avalonia.UnitTests/MockAssetLoader.cs
  99. 5 0
      tests/Avalonia.UnitTests/UnitTestApplication.cs

+ 3 - 0
.gitmodules

@@ -4,3 +4,6 @@
 [submodule "nukebuild/Numerge"]
 	path = nukebuild/Numerge
 	url = https://github.com/kekekeks/Numerge.git
+[submodule "src/Markup/Avalonia.Markup.Xaml/XamlIl/xamlil.github"]
+	path = src/Markup/Avalonia.Markup.Xaml/XamlIl/xamlil.github
+	url = https://github.com/kekekeks/XamlIl.git

+ 3 - 3
build/EmbedXaml.props

@@ -4,8 +4,8 @@
      <Compile Update="**\*.xaml.cs">
       <DependentUpon>%(Filename)</DependentUpon>
     </Compile>
-    <EmbeddedResource Include="**\*.xaml">
+    <AvaloniaResource Include="**\*.xaml">
       <SubType>Designer</SubType>
-    </EmbeddedResource>
+    </AvaloniaResource>
   </ItemGroup>
-</Project>
+</Project>

+ 5 - 0
build/SampleApp.props

@@ -5,4 +5,9 @@
   <ItemGroup>
     <ProjectReference Include="$(MSBuildThisFileDirectory)..\src\Avalonia.Desktop\Avalonia.Desktop.csproj" />
   </ItemGroup>
+  <Target Name="GatherReferences" AfterTargets="CoreCompile">
+    <WriteLinesToFile File="$(TargetPath).refs"
+                      Lines="@(ReferencePathWithRefAssemblies)"
+                      Overwrite="true" />
+  </Target>
 </Project>

+ 3 - 3
dirs.proj

@@ -6,12 +6,12 @@
     <ProjectReference Include="packages/**/*.*proj" />
     <ProjectReference Remove="**/*.shproj" />
     <ProjectReference Remove="src/Markup/Avalonia.Markup.Xaml/PortableXaml/**/*.*proj" />
+    <ProjectReference Remove="src/Markup/Avalonia.Markup.Xaml/XamlIl/**/*.*proj" />
   </ItemGroup>
-  <ItemGroup Condition="!Exists('$(MSBuildExtensionsPath)\Xamarin\Android')">
+<!-- Disabled on CI because of ancient MSBuild project format -->
+  <ItemGroup>
     <ProjectReference Remove="src/Android/**/*.*proj" />
     <ProjectReference Remove="samples/ControlCatalog.Android/ControlCatalog.Android.csproj" />
-  </ItemGroup>
-  <ItemGroup Condition="!Exists('$(MSBuildExtensionsPath)\Xamarin\iOS')">
     <ProjectReference Remove="src/iOS/**/*.*proj" />
     <ProjectReference Remove="samples/ControlCatalog.iOS/ControlCatalog.iOS.csproj" />
   </ItemGroup>

+ 37 - 2
packages/Avalonia/AvaloniaBuildTasks.targets

@@ -8,6 +8,10 @@
              AssemblyFile="$(AvaloniaBuildTasksLocation)"
              />
 
+  <UsingTask TaskName="CompileAvaloniaXamlTask"
+             AssemblyFile="$(AvaloniaBuildTasksLocation)"
+             />
+
 
   <Target Name="AddAvaloniaResources" BeforeTargets="ResolveReferences">
     <PropertyGroup>
@@ -20,11 +24,15 @@
     </ItemGroup>
   </Target>
   
+  <PropertyGroup>
+    <BuildAvaloniaResourcesDependsOn>$(BuildAvaloniaResourcesDependsOn);AddAvaloniaResources;ResolveReferences</BuildAvaloniaResourcesDependsOn>
+  </PropertyGroup>
+  
   <Target Name="GenerateAvaloniaResources" 
           BeforeTargets="CoreCompile;CoreResGen"
           Inputs="@(AvaloniaResource);$(MSBuildAllProjects)"
           Outputs="$(AvaloniaResourcesTemporaryFilePath)"
-          DependsOnTargets="$(BuildAvaloniaResourcesDependsOn);AddAvaloniaResources;ResolveReferences">
+          DependsOnTargets="$(BuildAvaloniaResourcesDependsOn)">
     <GenerateAvaloniaResourcesTask
       Condition="'$(_AvaloniaUseExternalMSBuild)' != 'true'"
       Output="$(AvaloniaResourcesTemporaryFilePath)"
@@ -33,9 +41,36 @@
       EmbeddedResources="@(EmbeddedResources)"/>
     <Exec 
       Condition="'$(_AvaloniaUseExternalMSBuild)' == 'true'"
-      Command="dotnet msbuild /nodereuse:false $(MSBuildProjectFile) /t:GenerateAvaloniaResources /p:_AvaloniaForceInternalMSBuild=true /p:Configuration=$(Configuration)"/>
+      Command="dotnet msbuild /nodereuse:false $(MSBuildProjectFile) /t:GenerateAvaloniaResources /p:_AvaloniaForceInternalMSBuild=true /p:Configuration=$(Configuration) /p:TargetFramework=$(TargetFramework) /p:BuildProjectReferences=false"/>
 
   </Target>
+
+  <Target
+    Name="CompileAvaloniaXaml"
+    AfterTargets="AfterCompile"
+    Condition="Exists('@(IntermediateAssembly)') And $(DesignTimeBuild) != true And $(EnableAvaloniaXamlCompilation) != false"
+    >
+    <PropertyGroup>
+      <AvaloniaXamlReferencesTemporaryFilePath Condition="'$(AvaloniaXamlReferencesTemporaryFilePath)' == ''">$(IntermediateOutputPath)/Avalonia/references</AvaloniaXamlReferencesTemporaryFilePath>
+      <AvaloniaXamlOriginalCopyFilePath Condition="'$(AvaloniaXamlOriginalCopyFilePath)' == ''">$(IntermediateOutputPath)/Avalonia/original.dll</AvaloniaXamlOriginalCopyFilePath>
+    </PropertyGroup>
+    <WriteLinesToFile
+      Condition="'$(_AvaloniaForceInternalMSBuild)' != 'true'"
+      File="$(AvaloniaXamlReferencesTemporaryFilePath)"
+      Lines="@(ReferencePathWithRefAssemblies)"
+      Overwrite="true" />
+    <CompileAvaloniaXamlTask
+      Condition="'$(_AvaloniaUseExternalMSBuild)' != 'true'"
+      AssemblyFile="@(IntermediateAssembly)"
+      ReferencesFilePath="$(AvaloniaXamlReferencesTemporaryFilePath)"
+      OriginalCopyPath="$(AvaloniaXamlOriginalCopyFilePath)"
+      ProjectDirectory="$(MSBuildProjectDirectory)"
+    />
+    <Exec
+      Condition="'$(_AvaloniaUseExternalMSBuild)' == 'true'"
+      Command="dotnet msbuild /nodereuse:false $(MSBuildProjectFile) /t:CompileAvaloniaXaml /p:_AvaloniaForceInternalMSBuild=true /p:Configuration=$(Configuration) /p:TargetFramework=$(TargetFramework) /p:BuildProjectReferences=false"/>
+  </Target>
+
   
   <ItemGroup>
     <UpToDateCheckInput Include="@(AvaloniaResource)" />

+ 1 - 0
samples/ControlCatalog.NetCore/ControlCatalog.NetCore.csproj

@@ -3,6 +3,7 @@
   <PropertyGroup>
     <OutputType>Exe</OutputType>
     <TargetFramework>netcoreapp2.0</TargetFramework>
+    <TargetLatestRuntimePatch>true</TargetLatestRuntimePatch>
   </PropertyGroup>
 
   <ItemGroup>

+ 1 - 1
samples/ControlCatalog/App.xaml

@@ -4,7 +4,7 @@
   <Application.Styles>
       <StyleInclude Source="avares://Avalonia.Themes.Default/DefaultTheme.xaml"/>
       <StyleInclude Source="avares://Avalonia.Themes.Default/Accents/BaseLight.xaml"/>
-      <StyleInclude Source="resm:Avalonia.Controls.DataGrid.Themes.Default.xaml?assembly=Avalonia.Controls.DataGrid"/>
+      <StyleInclude Source="avares://Avalonia.Controls.DataGrid/Themes/Default.xaml"/>
     <Style Selector="TextBlock.h1">
       <Setter Property="FontSize" Value="{DynamicResource FontSizeLarge}"/>
       <Setter Property="FontWeight" Value="Medium"/>

+ 15 - 8
samples/ControlCatalog/MainView.xaml.cs

@@ -1,8 +1,11 @@
+using System;
 using System.Collections;
 using Avalonia;
 using Avalonia.Controls;
 using Avalonia.Markup.Xaml;
+using Avalonia.Markup.Xaml.MarkupExtensions;
 using Avalonia.Markup.Xaml.Styling;
+using Avalonia.Markup.Xaml.XamlIl;
 using Avalonia.Platform;
 using ControlCatalog.Pages;
 
@@ -12,7 +15,7 @@ namespace ControlCatalog
     {
         public MainView()
         {
-            this.InitializeComponent();
+            AvaloniaXamlLoader.Load(this);
             if (AvaloniaLocator.Current.GetService<IRuntimePlatform>().GetRuntimeInfo().IsDesktop)
             {
                 IList tabItems = ((IList)this.FindControl<TabControl>("Sidebar").Items);
@@ -28,8 +31,17 @@ namespace ControlCatalog
                 });
 
             }
-            var light = AvaloniaXamlLoader.Parse<StyleInclude>(@"<StyleInclude xmlns='https://github.com/avaloniaui' Source='resm:Avalonia.Themes.Default.Accents.BaseLight.xaml?assembly=Avalonia.Themes.Default'/>");
-            var dark = AvaloniaXamlLoader.Parse<StyleInclude>(@"<StyleInclude xmlns='https://github.com/avaloniaui' Source='resm:Avalonia.Themes.Default.Accents.BaseDark.xaml?assembly=Avalonia.Themes.Default'/>");
+
+            var light = new StyleInclude(new Uri("resm:Styles?assembly=ControlCatalog"))
+            {
+                Source = new Uri("resm:Avalonia.Themes.Default.Accents.BaseLight.xaml?assembly=Avalonia.Themes.Default")
+            };
+            var dark = new StyleInclude(new Uri("resm:Styles?assembly=ControlCatalog"))
+            {
+                Source = new Uri("resm:Avalonia.Themes.Default.Accents.BaseDark.xaml?assembly=Avalonia.Themes.Default")
+            };
+
+            
             var themes = this.Find<ComboBox>("Themes");
             themes.SelectionChanged += (sender, e) =>
             {
@@ -45,10 +57,5 @@ namespace ControlCatalog
             };
             Styles.Add(light);
         }
-
-        private void InitializeComponent()
-        {
-            AvaloniaXamlLoader.Load(this);
-        }
     }
 }

+ 1 - 0
samples/ControlCatalog/MainWindow.xaml

@@ -1,4 +1,5 @@
 <Window xmlns="https://github.com/avaloniaui" MinWidth="500" MinHeight="300"
+        xmlns:pages="clr-namespace:ControlCatalog.Pages"
         Title="Avalonia Control Gallery"
         Icon="/Assets/test_icon.ico"
         xmlns:local="clr-namespace:ControlCatalog"

+ 0 - 9
samples/ControlCatalog/Pages/ButtonPage.xaml.cs

@@ -5,14 +5,5 @@ namespace ControlCatalog.Pages
 {
     public class ButtonPage : UserControl
     {
-        public ButtonPage()
-        {
-            this.InitializeComponent();
-        }
-
-        private void InitializeComponent()
-        {
-            AvaloniaXamlLoader.Load(this);
-        }
     }
 }

+ 1 - 1
samples/ControlCatalog/Pages/ButtonSpinnerPage.xaml.cs

@@ -18,7 +18,7 @@ namespace ControlCatalog.Pages
             AvaloniaXamlLoader.Load(this);
         }
 
-        private void OnSpin(object sender, SpinEventArgs e)
+        public void OnSpin(object sender, SpinEventArgs e)
         {
             var spinner = (ButtonSpinner)sender;
             var txtBox = (TextBlock)spinner.Content;

+ 1 - 1
samples/ControlCatalog/SideBar.xaml

@@ -1,6 +1,6 @@
 <Styles xmlns="https://github.com/avaloniaui"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
-        x:Class="ControlCatalog.SideBar">
+>
     <Design.PreviewWith>
         <Border Padding="20">
             <TabControl Classes="sidebar">

+ 11 - 10
src/Avalonia.Base/AvaloniaProperty.cs

@@ -19,7 +19,7 @@ namespace Avalonia
         /// <summary>
         /// Represents an unset property value.
         /// </summary>
-        public static readonly object UnsetValue = new Unset();
+        public static readonly object UnsetValue = new UnsetValueType();
 
         private static int s_nextId;
         private readonly Subject<AvaloniaPropertyChangedEventArgs> _initialized;
@@ -546,16 +546,17 @@ namespace Avalonia
             }
         }
 
+        
+    }
+    /// <summary>
+    /// Class representing the <see cref="AvaloniaProperty.UnsetValue"/>.
+    /// </summary>
+    public class UnsetValueType
+    {
         /// <summary>
-        /// Class representing the <see cref="UnsetValue"/>.
+        /// Returns the string representation of the <see cref="AvaloniaProperty.UnsetValue"/>.
         /// </summary>
-        private class Unset
-        {
-            /// <summary>
-            /// Returns the string representation of the <see cref="UnsetValue"/>.
-            /// </summary>
-            /// <returns>The string "(unset)".</returns>
-            public override string ToString() => "(unset)";
-        }
+        /// <returns>The string "(unset)".</returns>
+        public override string ToString() => "(unset)";
     }
 }

+ 4 - 1
src/Avalonia.Base/Data/Core/ExpressionParseException.cs

@@ -9,7 +9,10 @@ namespace Avalonia.Data.Core
     /// Exception thrown when <see cref="ExpressionObserver"/> could not parse the provided
     /// expression string.
     /// </summary>
-    public class ExpressionParseException : Exception
+#if !BUILDTASK
+    public
+#endif
+    class ExpressionParseException : Exception
     {
         /// <summary>
         /// Initializes a new instance of the <see cref="ExpressionParseException"/> class.

+ 10 - 0
src/Avalonia.Base/Metadata/UsableDuringInitializationAttribute.cs

@@ -0,0 +1,10 @@
+using System;
+
+namespace Avalonia.Metadata
+{
+    [AttributeUsage(AttributeTargets.Class)]
+    public class UsableDuringInitializationAttribute : Attribute
+    {
+        
+    }
+}

+ 10 - 0
src/Avalonia.Base/Platform/IAssetLoader.cs

@@ -61,6 +61,16 @@ namespace Avalonia.Platform
         /// </exception>
         (Stream stream, Assembly assembly) OpenAndGetAssembly(Uri uri, Uri baseUri = null);
 
+        /// <summary>
+        /// Extracts assembly information from URI
+        /// </summary>
+        /// <param name="uri">The URI.</param>
+        /// <param name="baseUri">
+        /// A base URI to use if <paramref name="uri"/> is relative.
+        /// </param>
+        /// <returns>Assembly associated with the Uri</returns>
+        Assembly GetAssembly(Uri uri, Uri baseUri = null);
+
         /// <summary>
         /// Gets all assets of a folder and subfolders that match specified uri.
         /// </summary>

+ 30 - 0
src/Avalonia.Base/Utilities/AvaloniaResourcesIndex.cs

@@ -46,6 +46,36 @@ namespace Avalonia.Utilities
                     Entries = entries
                 });
         }
+
+        public static byte[] Create(Dictionary<string, byte[]> data)
+        {
+            var sources = data.ToList();
+            var offsets = new Dictionary<string, int>();
+            var coffset = 0;
+            foreach (var s in sources)
+            {
+                offsets[s.Key] = coffset;
+                coffset += s.Value.Length;
+            }
+            var index = sources.Select(s => new AvaloniaResourcesIndexEntry
+            {
+                Path = s.Key,
+                Size = s.Value.Length,
+                Offset = offsets[s.Key]
+            }).ToList();
+            var output = new MemoryStream();
+            var ms = new MemoryStream();
+            AvaloniaResourcesIndexReaderWriter.Write(ms, index);
+            new BinaryWriter(output).Write((int)ms.Length);
+            ms.Position = 0;
+            ms.CopyTo(output);
+            foreach (var s in sources)
+            {
+                output.Write(s.Value,0,s.Value.Length);
+            }
+
+            return output.ToArray();
+        }
     }
 
     [DataContract]

+ 4 - 1
src/Avalonia.Base/Utilities/CharacterReader.cs

@@ -5,7 +5,10 @@ using System;
 
 namespace Avalonia.Utilities
 {
-    public ref struct CharacterReader
+#if !BUILDTASK
+    public
+#endif
+    ref struct CharacterReader
     {
         private ReadOnlySpan<char> _s;
 

+ 4 - 1
src/Avalonia.Base/Utilities/IdentifierParser.cs

@@ -6,7 +6,10 @@ using System.Globalization;
 
 namespace Avalonia.Utilities
 {
-    public static class IdentifierParser
+#if !BUILDTASK
+    public
+#endif
+    static class IdentifierParser
     {
         public static ReadOnlySpan<char> ParseIdentifier(this ref CharacterReader r)
         {

+ 57 - 5
src/Avalonia.Build.Tasks/Avalonia.Build.Tasks.csproj

@@ -1,9 +1,13 @@
-<Project Sdk="Microsoft.NET.Sdk">
-
+<Project Sdk="Microsoft.NET.Sdk">
     <PropertyGroup>
-        <TargetFramework>netstandard2.0</TargetFramework>
+        <TargetFrameworks>netstandard2.0</TargetFrameworks>
+        <TargetFrameworks Condition="$(Configuration) == 'Debug'">netstandard2.0;netcoreapp2.0</TargetFrameworks>
+        <OutputType>exe</OutputType>
+        <GenerateDocumentationFile>false</GenerateDocumentationFile>
         <BuildOutputTargetFolder>tools</BuildOutputTargetFolder>
-        <DefineConstants>$(DefineConstants);BUILDTASK</DefineConstants>
+        <DefineConstants>$(DefineConstants);BUILDTASK;XAMLIL_CECIL_INTERNAL;XAMLIL_INTERNAL</DefineConstants>
+        <CopyLocalLockFileAssemblies Condition="$(TargetFramework) == 'netstandard2.0'">true</CopyLocalLockFileAssemblies>
+        <NoWarn>NU1605</NoWarn>
     </PropertyGroup>
 
     <ItemGroup>
@@ -13,6 +17,54 @@
       <Compile Include="../Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaResourceXamlInfo.cs">
         <Link>Shared/AvaloniaResourceXamlInfo.cs</Link>
       </Compile>
-      <PackageReference Include="Microsoft.Build.Framework" Version="15.1.548" />
+      <Compile Include="../Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/**/*.cs">
+        <Link>XamlIlExtensions/%(RecursiveDir)%(FileName)%(Extension)</Link>
+      </Compile>
+      <Compile Remove="external/cecil/**/*.*" />
+      <Compile Include="../Markup/Avalonia.Markup.Xaml/XamlIl\xamlil.github\src\XamlIl\**\*.cs">
+        <Link>XamlIl/%(RecursiveDir)%(FileName)%(Extension)</Link>
+      </Compile>
+      <Compile Include="../Markup/Avalonia.Markup.Xaml/XamlIl\xamlil.github\src\XamlIl.Cecil\**\*.cs">
+        <Link>XamlIl.Cecil/%(RecursiveDir)%(FileName)%(Extension)</Link>
+      </Compile>
+      <Compile Include="../Markup/Avalonia.Markup\Markup\Parsers\SelectorGrammar.cs">
+        <Link>Markup/%(RecursiveDir)%(FileName)%(Extension)</Link>
+      </Compile>
+      <Compile Include="../Markup/Avalonia.Markup.Xaml/Parsers/PropertyParser.cs">
+        <Link>Markup/%(RecursiveDir)%(FileName)%(Extension)</Link>
+      </Compile>
+      <Compile Include="../Avalonia.Base/Data/Core/ExpressionParseException.cs">
+        <Link>Markup/%(RecursiveDir)%(FileName)%(Extension)</Link>
+      </Compile>
+      <Compile Include="../Avalonia.Base/Utilities/CharacterReader.cs">
+        <Link>Markup/%(RecursiveDir)%(FileName)%(Extension)</Link>
+      </Compile>      
+      <Compile Include="../Avalonia.Base/Utilities/IdentifierParser.cs">
+        <Link>Markup/%(RecursiveDir)%(FileName)%(Extension)</Link>
+      </Compile>
+      
+      <Compile Remove="../Markup/Avalonia.Markup.Xaml/XamlIl\xamlil.github\**\obj\**\*.cs" />
+      <Compile Remove="../Markup/Avalonia.Markup.Xaml/XamlIl\xamlil.github\src\XamlIl\TypeSystem\SreTypeSystem.cs" />
+      <PackageReference Include="Avalonia.Unofficial.Cecil" Version="20190417.2.0" PrivateAssets="All" />
+      <PackageReference Condition="$(TargetFramework) == 'netstandard2.0'" Include="ILRepack.MSBuild.Task" Version="2.0.13" PrivateAssets="All" />
+      <PackageReference Include="Microsoft.Build.Framework" Version="15.1.548" PrivateAssets="All" />
+    </ItemGroup>
+
+  <Target Name="ILRepack" AfterTargets="Build" Condition="$(TargetFramework) == 'netstandard2.0'">
+
+    <PropertyGroup>
+      <WorkingDirectory>$(MSBuildThisFileDirectory)bin\$(Configuration)\$(TargetFramework)</WorkingDirectory>
+    </PropertyGroup>
+
+    <ItemGroup>
+      <InputAssemblies Include="Mono.Cecil.dll" />
+    </ItemGroup>
+    <ILRepack OutputType="$(OutputType)" MainAssembly="$(AssemblyName).dll" OutputAssembly="$(AssemblyName).dll" InputAssemblies="@(InputAssemblies)" WorkingDirectory="$(WorkingDirectory)" />
+    <ItemGroup>
+      <DeleteNonNeededResults Include="$(WorkingDirectory)\*.dll" />
+      <DeleteNonNeededResults Remove="$(WorkingDirectory)\Avalonia.Build.Tasks.dll" />
     </ItemGroup>
+    <Delete Files="@(DeleteNonNeededResults)" />
+
+  </Target>
 </Project>

+ 73 - 0
src/Avalonia.Build.Tasks/CompileAvaloniaXamlTask.cs

@@ -0,0 +1,73 @@
+using System;
+using System.Diagnostics;
+using System.IO;
+using System.Linq;
+using System.Reflection;
+using System.Threading;
+using Microsoft.Build.Framework;
+
+namespace Avalonia.Build.Tasks
+{
+    public class CompileAvaloniaXamlTask: ITask
+    {
+        public bool Execute()
+        {
+            OutputPath = OutputPath ?? AssemblyFile;
+            var outputPdb = GetPdbPath(OutputPath);
+            var input = AssemblyFile;
+            var inputPdb = GetPdbPath(input);
+            // Make a copy and delete the original file to prevent MSBuild from thinking that everything is OK 
+            if (OriginalCopyPath != null)
+            {
+                File.Copy(AssemblyFile, OriginalCopyPath, true);
+                input = OriginalCopyPath;
+                File.Delete(AssemblyFile);
+
+                if (File.Exists(inputPdb))
+                {
+                    var copyPdb = GetPdbPath(OriginalCopyPath);
+                    File.Copy(inputPdb, copyPdb, true);
+                    File.Delete(inputPdb);
+                    inputPdb = copyPdb;
+                }
+            }
+
+            var res = XamlCompilerTaskExecutor.Compile(BuildEngine, input,
+                File.ReadAllLines(ReferencesFilePath).Where(l => !string.IsNullOrWhiteSpace(l)).ToArray(),
+                ProjectDirectory, OutputPath);
+            if (!res.Success)
+                return false;
+            if (!res.WrittenFile)
+            {
+                File.Copy(input, OutputPath, true);
+                if(File.Exists(inputPdb))
+                    File.Copy(inputPdb, outputPdb, true);
+            }
+            return true;
+        }
+
+        string GetPdbPath(string p)
+        {
+            var d = Path.GetDirectoryName(p);
+            var f = Path.GetFileNameWithoutExtension(p);
+            var rv = f + ".pdb";
+            if (d != null)
+                rv = Path.Combine(d, rv);
+            return rv;
+        }
+        
+        [Required]
+        public string AssemblyFile { get; set; }
+        [Required]
+        public string ReferencesFilePath { get; set; }
+        [Required]
+        public string OriginalCopyPath { get; set; }
+        [Required]
+        public string ProjectDirectory { get; set; }
+        
+        public string OutputPath { get; set; }
+        
+        public IBuildEngine BuildEngine { get; set; }
+        public ITaskHost HostObject { get; set; }
+    }
+}

+ 2 - 1
src/Avalonia.Build.Tasks/Extensions.cs

@@ -1,8 +1,9 @@
+using System;
 using Microsoft.Build.Framework;
 
 namespace Avalonia.Build.Tasks
 {
-    public static class Extensions
+    static class Extensions
     {
         static string FormatErrorCode(BuildEngineErrorCode code) => $"AVLN:{(int)code:0000}";
 

+ 61 - 0
src/Avalonia.Build.Tasks/Program.cs

@@ -0,0 +1,61 @@
+using System;
+using System.Collections;
+using System.IO;
+using Microsoft.Build.Framework;
+
+namespace Avalonia.Build.Tasks
+{
+    public class Program
+    {
+        static int Main(string[] args)
+        {
+            if (args.Length != 3)
+            {
+                Console.Error.WriteLine("input references output");
+                return 1;
+            }
+
+            return new CompileAvaloniaXamlTask()
+            {
+                AssemblyFile = args[0],
+                ReferencesFilePath = args[1],
+                OutputPath = args[2],
+                BuildEngine = new ConsoleBuildEngine(),
+                ProjectDirectory = Directory.GetCurrentDirectory()
+            }.Execute() ?
+                0 :
+                2;
+        }
+
+        class ConsoleBuildEngine : IBuildEngine
+        {
+            public void LogErrorEvent(BuildErrorEventArgs e)
+            {
+                Console.WriteLine($"ERROR: {e.Code} {e.Message} in {e.File} {e.LineNumber}:{e.ColumnNumber}-{e.EndLineNumber}:{e.EndColumnNumber}");
+            }
+
+            public void LogWarningEvent(BuildWarningEventArgs e)
+            {
+                Console.WriteLine($"WARNING: {e.Code} {e.Message} in {e.File} {e.LineNumber}:{e.ColumnNumber}-{e.EndLineNumber}:{e.EndColumnNumber}");
+            }
+
+            public void LogMessageEvent(BuildMessageEventArgs e)
+            {
+                Console.WriteLine($"MESSAGE: {e.Code} {e.Message} in {e.File} {e.LineNumber}:{e.ColumnNumber}-{e.EndLineNumber}:{e.EndColumnNumber}");
+            }
+
+            public void LogCustomEvent(CustomBuildEventArgs e)
+            {
+                Console.WriteLine($"CUSTOM: {e.Message}");
+            }
+
+            public bool BuildProjectFile(string projectFileName, string[] targetNames, IDictionary globalProperties,
+                IDictionary targetOutputs) => throw new NotSupportedException();
+
+            public bool ContinueOnError { get; }
+            public int LineNumberOfTaskNode { get; }
+            public int ColumnNumberOfTaskNode { get; }
+            public string ProjectFileOfTaskNode { get; }
+        }
+    }
+}

+ 73 - 0
src/Avalonia.Build.Tasks/SpanCompat.cs

@@ -0,0 +1,73 @@
+namespace System
+{
+    // This is a hack to enable our span code to work inside MSBuild task without referencing System.Memory
+    struct ReadOnlySpan<T>
+    {
+        private string _s;
+        private int _start;
+        private int _length;
+        public int Length => _length;
+
+        public ReadOnlySpan(string s) : this(s, 0, s.Length)
+        {
+            
+        }
+        public ReadOnlySpan(string s, int start, int len)
+        {
+            _s = s;
+            _length = len;
+            _start = start;
+            if (_start > s.Length)
+                _length = 0;
+            else if (_start + _length > s.Length)
+                _length = s.Length - _start;
+        }
+
+        public char this[int c] => _s[_start + c];
+
+        public bool IsEmpty => _length == 0;
+        
+        public ReadOnlySpan<char> Slice(int start, int len)
+        {
+            return new ReadOnlySpan<char>(_s, _start + start, len);
+        }
+
+        public static ReadOnlySpan<char> Empty => default;
+        
+        public ReadOnlySpan<char> Slice(int start)
+        {
+            return new ReadOnlySpan<char>(_s, _start + start, _length - start);
+        }
+
+        public bool SequenceEqual(ReadOnlySpan<char> other)
+        {
+            if (_length != other.Length)
+                return false;
+            for(var c=0; c<_length;c++)
+                if (this[c] != other[c])
+                    return false;
+            return true;
+        }
+        
+        public ReadOnlySpan<char> TrimStart()
+        {
+            int start = 0;
+            for (; start < Length; start++)
+            {
+                if (!char.IsWhiteSpace(this[start]))
+                {
+                    break;
+                }
+            }
+            return Slice(start);
+        }
+
+        public override string ToString() => _length == 0 ? string.Empty : _s.Substring(_start, _length);
+    }
+
+    static class SpanCompatExtensions
+    {
+        public static ReadOnlySpan<char> AsSpan(this string s) => new ReadOnlySpan<char>(s);
+    }
+
+}

+ 149 - 0
src/Avalonia.Build.Tasks/XamlCompilerTaskExecutor.Helpers.cs

@@ -0,0 +1,149 @@
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using Avalonia.Utilities;
+using Mono.Cecil;
+using Mono.Cecil.Cil;
+using XamlIl.TypeSystem;
+
+namespace Avalonia.Build.Tasks
+{
+    public static partial class XamlCompilerTaskExecutor
+    {
+        interface IResource : IFileSource
+        {
+            string Uri { get; }
+            string Name { get; }
+            void Remove();
+
+        }
+
+        interface IResourceGroup
+        {
+            string Name { get; }
+            IEnumerable<IResource> Resources { get; }
+        }
+        
+        class EmbeddedResources : IResourceGroup
+        {
+            private readonly AssemblyDefinition _asm;
+            public string Name => "EmbeddedResource";
+
+            public IEnumerable<IResource> Resources => _asm.MainModule.Resources.OfType<EmbeddedResource>()
+                .Select(r => new WrappedResource(_asm, r)).ToList();
+
+            public EmbeddedResources(AssemblyDefinition asm)
+            {
+                _asm = asm;
+            }
+            class WrappedResource : IResource
+            {
+                private readonly AssemblyDefinition _asm;
+                private readonly EmbeddedResource _res;
+
+                public WrappedResource(AssemblyDefinition asm, EmbeddedResource res)
+                {
+                    _asm = asm;
+                    _res = res;
+                }
+
+                public string Uri => $"resm:{Name}?assembly={_asm.Name.Name}";
+                public string Name => _res.Name;
+                public string FilePath => Name;
+                public byte[] FileContents => _res.GetResourceData();
+
+                public void Remove() => _asm.MainModule.Resources.Remove(_res);
+            }
+        }
+
+        class AvaloniaResources : IResourceGroup
+        {
+            private readonly AssemblyDefinition _asm;
+            Dictionary<string, AvaloniaResource> _resources = new Dictionary<string, AvaloniaResource>();
+            private EmbeddedResource _embedded;
+            public AvaloniaResources(AssemblyDefinition asm, string projectDir)
+            {
+                _asm = asm;
+                _embedded = ((EmbeddedResource)asm.MainModule.Resources.FirstOrDefault(r =>
+                    r.ResourceType == ResourceType.Embedded && r.Name == "!AvaloniaResources"));
+                if (_embedded == null)
+                    return;
+                using (var stream = _embedded.GetResourceStream())
+                {
+                    var br = new BinaryReader(stream);
+                    var index = AvaloniaResourcesIndexReaderWriter.Read(new MemoryStream(br.ReadBytes(br.ReadInt32())));
+                    var baseOffset = stream.Position;
+                    foreach (var e in index)
+                    {
+                        stream.Position = e.Offset + baseOffset;
+                        _resources[e.Path] = new AvaloniaResource(this, projectDir, e.Path, br.ReadBytes(e.Size));
+                    }
+                }
+            }
+
+            public void Save()
+            {
+                if (_embedded != null)
+                {
+                    _asm.MainModule.Resources.Remove(_embedded);
+                    _embedded = null;
+                }
+
+                if (_resources.Count == 0)
+                    return;
+
+                _embedded = new EmbeddedResource("!AvaloniaResources", ManifestResourceAttributes.Public,
+                    AvaloniaResourcesIndexReaderWriter.Create(_resources.ToDictionary(x => x.Key,
+                        x => x.Value.FileContents)));
+                _asm.MainModule.Resources.Add(_embedded);
+            }
+
+            public string Name => "AvaloniaResources";
+            public IEnumerable<IResource> Resources => _resources.Values.ToList();
+
+            class AvaloniaResource : IResource
+            {
+                private readonly AvaloniaResources _grp;
+                private readonly byte[] _data;
+
+                public AvaloniaResource(AvaloniaResources grp,
+                    string projectDir,
+                    string name, byte[] data)
+                {
+                    _grp = grp;
+                    _data = data;
+                    Name = name;
+                    FilePath = Path.Combine(projectDir, name.TrimStart('/'));
+                    Uri = $"avares://{grp._asm.Name.Name}/{name.TrimStart('/')}";
+                }
+                public string Uri { get; }
+                public string Name { get; }
+                public string FilePath { get; }
+                public byte[] FileContents => _data;
+
+                public void Remove() => _grp._resources.Remove(Name);
+            }
+        }
+
+        static void CopyDebugDocument(MethodDefinition method, MethodDefinition copyFrom)
+        {
+            if (!copyFrom.DebugInformation.HasSequencePoints)
+                return;
+            var dbg = method.DebugInformation;
+
+            dbg.Scope = new ScopeDebugInformation(method.Body.Instructions.First(), method.Body.Instructions.First())
+            {
+                End = new InstructionOffset(),
+                Import = new ImportDebugInformation()
+            };
+            dbg.SequencePoints.Add(new SequencePoint(method.Body.Instructions.First(),
+                copyFrom.DebugInformation.SequencePoints.First().Document)
+            {
+                StartLine = 0xfeefee,
+                EndLine = 0xfeefee
+            });
+
+        }
+    }
+ 
+}

+ 357 - 0
src/Avalonia.Build.Tasks/XamlCompilerTaskExecutor.cs

@@ -0,0 +1,357 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Reflection;
+using System.Text;
+using Avalonia.Markup.Xaml.XamlIl.CompilerExtensions;
+using Microsoft.Build.Framework;
+using Mono.Cecil;
+using XamlIl.TypeSystem;
+using Avalonia.Utilities;
+using Mono.Cecil.Cil;
+using Mono.Cecil.Rocks;
+using XamlIl;
+using XamlIl.Ast;
+using XamlIl.Parsers;
+using XamlIl.Transform;
+using FieldAttributes = Mono.Cecil.FieldAttributes;
+using MethodAttributes = Mono.Cecil.MethodAttributes;
+using TypeAttributes = Mono.Cecil.TypeAttributes;
+
+namespace Avalonia.Build.Tasks
+{
+    
+    public static partial class XamlCompilerTaskExecutor
+    {
+        static bool CheckXamlName(IResource r) => r.Name.ToLowerInvariant().EndsWith(".xaml")
+                                               || r.Name.ToLowerInvariant().EndsWith(".paml");
+        
+        public class CompileResult
+        {
+            public bool Success { get; set; }
+            public bool WrittenFile { get; }
+
+            public CompileResult(bool success, bool writtenFile = false)
+            {
+                Success = success;
+                WrittenFile = writtenFile;
+            }
+        }
+        
+        public static CompileResult Compile(IBuildEngine engine, string input, string[] references, string projectDirectory,
+            string output)
+        {
+            var typeSystem = new CecilTypeSystem(references.Concat(new[] {input}), input);
+            var asm = typeSystem.TargetAssemblyDefinition;
+            var emres = new EmbeddedResources(asm);
+            var avares = new AvaloniaResources(asm, projectDirectory);
+            if (avares.Resources.Count(CheckXamlName) == 0 && emres.Resources.Count(CheckXamlName) == 0)
+                // Nothing to do
+                return new CompileResult(true);
+            
+            var xamlLanguage = AvaloniaXamlIlLanguage.Configure(typeSystem);
+            var compilerConfig = new XamlIlTransformerConfiguration(typeSystem,
+                typeSystem.TargetAssembly,
+                xamlLanguage,
+                XamlIlXmlnsMappings.Resolve(typeSystem, xamlLanguage),
+                AvaloniaXamlIlLanguage.CustomValueConverter);
+
+
+            var contextDef = new TypeDefinition("CompiledAvaloniaXaml", "XamlIlContext", 
+                TypeAttributes.Class, asm.MainModule.TypeSystem.Object);
+            asm.MainModule.Types.Add(contextDef);
+
+            var contextClass = XamlIlContextDefinition.GenerateContextClass(typeSystem.CreateTypeBuilder(contextDef), typeSystem,
+                xamlLanguage);
+
+            var compiler = new AvaloniaXamlIlCompiler(compilerConfig, contextClass);
+
+            var editorBrowsableAttribute = typeSystem
+                .GetTypeReference(typeSystem.FindType("System.ComponentModel.EditorBrowsableAttribute"))
+                .Resolve();
+            var editorBrowsableCtor =
+                asm.MainModule.ImportReference(editorBrowsableAttribute.GetConstructors()
+                    .First(c => c.Parameters.Count == 1));
+
+            var runtimeHelpers = typeSystem.GetType("Avalonia.Markup.Xaml.XamlIl.Runtime.XamlIlRuntimeHelpers");
+            var rootServiceProviderField = asm.MainModule.ImportReference(
+                typeSystem.GetTypeReference(runtimeHelpers).Resolve().Fields
+                    .First(x => x.Name == "RootServiceProviderV1"));
+            
+            var loaderDispatcherDef = new TypeDefinition("CompiledAvaloniaXaml", "!XamlLoader",
+                TypeAttributes.Class, asm.MainModule.TypeSystem.Object);
+
+
+            loaderDispatcherDef.CustomAttributes.Add(new CustomAttribute(editorBrowsableCtor)
+            {
+                ConstructorArguments = {new CustomAttributeArgument(editorBrowsableCtor.Parameters[0].ParameterType, 1)}
+            });
+
+
+            var loaderDispatcherMethod = new MethodDefinition("TryLoad",
+                MethodAttributes.Static | MethodAttributes.Public,
+                asm.MainModule.TypeSystem.Object)
+            {
+                Parameters = {new ParameterDefinition(asm.MainModule.TypeSystem.String)}
+            };
+            loaderDispatcherDef.Methods.Add(loaderDispatcherMethod);
+            asm.MainModule.Types.Add(loaderDispatcherDef);
+
+            var stringEquals = asm.MainModule.ImportReference(asm.MainModule.TypeSystem.String.Resolve().Methods.First(
+                m =>
+                    m.IsStatic && m.Name == "Equals" && m.Parameters.Count == 2 &&
+                    m.ReturnType.FullName == "System.Boolean"
+                    && m.Parameters[0].ParameterType.FullName == "System.String"
+                    && m.Parameters[1].ParameterType.FullName == "System.String"));
+            
+            bool CompileGroup(IResourceGroup group)
+            {
+                var typeDef = new TypeDefinition("CompiledAvaloniaXaml", "!"+ group.Name,
+                    TypeAttributes.Class, asm.MainModule.TypeSystem.Object);
+
+                typeDef.CustomAttributes.Add(new CustomAttribute(editorBrowsableCtor)
+                {
+                    ConstructorArguments = {new CustomAttributeArgument(editorBrowsableCtor.Parameters[0].ParameterType, 1)}
+                });
+                asm.MainModule.Types.Add(typeDef);
+                var builder = typeSystem.CreateTypeBuilder(typeDef);
+                
+                foreach (var res in group.Resources.Where(CheckXamlName))
+                {
+                    try
+                    {
+                        // StreamReader is needed here to handle BOM
+                        var xaml = new StreamReader(new MemoryStream(res.FileContents)).ReadToEnd();
+                        var parsed = XDocumentXamlIlParser.Parse(xaml);
+
+                        var initialRoot = (XamlIlAstObjectNode)parsed.Root;
+                        
+                        
+                        var precompileDirective = initialRoot.Children.OfType<XamlIlAstXmlDirective>()
+                            .FirstOrDefault(d => d.Namespace == XamlNamespaces.Xaml2006 && d.Name == "Precompile");
+                        if (precompileDirective != null)
+                        {
+                            var precompileText = (precompileDirective.Values[0] as XamlIlAstTextNode)?.Text.Trim()
+                                .ToLowerInvariant();
+                            if (precompileText == "false")
+                                continue;
+                            if (precompileText != "true")
+                                throw new XamlIlParseException("Invalid value for x:Precompile", precompileDirective);
+                        }
+                        
+                        var classDirective = initialRoot.Children.OfType<XamlIlAstXmlDirective>()
+                            .FirstOrDefault(d => d.Namespace == XamlNamespaces.Xaml2006 && d.Name == "Class");
+                        IXamlIlType classType = null;
+                        if (classDirective != null)
+                        {
+                            if (classDirective.Values.Count != 1 || !(classDirective.Values[0] is XamlIlAstTextNode tn))
+                                throw new XamlIlParseException("x:Class should have a string value", classDirective);
+                            classType = typeSystem.TargetAssembly.FindType(tn.Text);
+                            if (classType == null)
+                                throw new XamlIlParseException($"Unable to find type `{tn.Text}`", classDirective);
+                            initialRoot.Type = new XamlIlAstClrTypeReference(classDirective, classType, false);
+                            initialRoot.Children.Remove(classDirective);
+                        }
+                        
+                        
+                        compiler.Transform(parsed);
+                        var populateName = classType == null ? "Populate:" + res.Name : "!XamlIlPopulate";
+                        var buildName = classType == null ? "Build:" + res.Name : null; 
+                        
+                        var classTypeDefinition =
+                            classType == null ? null : typeSystem.GetTypeReference(classType).Resolve();
+
+
+                        var populateBuilder = classTypeDefinition == null ?
+                            builder :
+                            typeSystem.CreateTypeBuilder(classTypeDefinition);
+                        compiler.Compile(parsed, contextClass,
+                            compiler.DefinePopulateMethod(populateBuilder, parsed, populateName,
+                                classTypeDefinition == null),
+                            buildName == null ? null : compiler.DefineBuildMethod(builder, parsed, buildName, true),
+                            builder.DefineSubType(compilerConfig.WellKnownTypes.Object, "NamespaceInfo:" + res.Name,
+                                true),
+                            (closureName, closureBaseType) =>
+                                populateBuilder.DefineSubType(closureBaseType, closureName, false),
+                            res.Uri, res
+                        );
+                        
+                        
+                        if (classTypeDefinition != null)
+                        {
+                            var compiledPopulateMethod = typeSystem.GetTypeReference(populateBuilder).Resolve()
+                                .Methods.First(m => m.Name == populateName);
+
+                            var designLoaderFieldType = typeSystem
+                                .GetType("System.Action`1")
+                                .MakeGenericType(typeSystem.GetType("System.Object"));
+
+                            var designLoaderFieldTypeReference = (GenericInstanceType)typeSystem.GetTypeReference(designLoaderFieldType);
+                            designLoaderFieldTypeReference.GenericArguments[0] =
+                                asm.MainModule.ImportReference(designLoaderFieldTypeReference.GenericArguments[0]);
+                            designLoaderFieldTypeReference = (GenericInstanceType)
+                                asm.MainModule.ImportReference(designLoaderFieldTypeReference);
+                            
+                            var designLoaderLoad =
+                                typeSystem.GetMethodReference(
+                                    designLoaderFieldType.Methods.First(m => m.Name == "Invoke"));
+                            designLoaderLoad =
+                                asm.MainModule.ImportReference(designLoaderLoad);
+                            designLoaderLoad.DeclaringType = designLoaderFieldTypeReference;
+
+                            var designLoaderField = new FieldDefinition("!XamlIlPopulateOverride",
+                                FieldAttributes.Static | FieldAttributes.Private, designLoaderFieldTypeReference);
+                            classTypeDefinition.Fields.Add(designLoaderField);
+
+                            const string TrampolineName = "!XamlIlPopulateTrampoline";
+                            var trampoline = new MethodDefinition(TrampolineName,
+                                MethodAttributes.Static | MethodAttributes.Private, asm.MainModule.TypeSystem.Void);
+                            trampoline.Parameters.Add(new ParameterDefinition(classTypeDefinition));
+                            classTypeDefinition.Methods.Add(trampoline);
+
+                            var regularStart = Instruction.Create(OpCodes.Ldsfld, rootServiceProviderField);
+                            
+                            trampoline.Body.Instructions.Add(Instruction.Create(OpCodes.Ldsfld, designLoaderField));
+                            trampoline.Body.Instructions.Add(Instruction.Create(OpCodes.Brfalse, regularStart));
+                            trampoline.Body.Instructions.Add(Instruction.Create(OpCodes.Ldsfld, designLoaderField));
+                            trampoline.Body.Instructions.Add(Instruction.Create(OpCodes.Ldarg_0));
+                            trampoline.Body.Instructions.Add(Instruction.Create(OpCodes.Call, designLoaderLoad));
+                            trampoline.Body.Instructions.Add(Instruction.Create(OpCodes.Ret));
+                            
+                            trampoline.Body.Instructions.Add(regularStart);
+                            trampoline.Body.Instructions.Add(Instruction.Create(OpCodes.Ldarg_0));
+                            trampoline.Body.Instructions.Add(Instruction.Create(OpCodes.Call, compiledPopulateMethod));
+                            trampoline.Body.Instructions.Add(Instruction.Create(OpCodes.Ret));
+                            CopyDebugDocument(trampoline, compiledPopulateMethod);
+
+                            var foundXamlLoader = false;
+                            // Find AvaloniaXamlLoader.Load(this) and replace it with !XamlIlPopulateTrampoline(this)
+                            foreach (var method in classTypeDefinition.Methods
+                                .Where(m => !m.Attributes.HasFlag(MethodAttributes.Static)))
+                            {
+                                var i = method.Body.Instructions;
+                                for (var c = 1; c < i.Count; c++)
+                                {
+                                    if (i[c - 1].OpCode == OpCodes.Ldarg_0
+                                        && i[c].OpCode == OpCodes.Call)
+                                    {
+                                        var op = i[c].Operand as MethodReference;
+                                        
+                                        // TODO: Throw an error
+                                        // This usually happens when same XAML resource was added twice for some weird reason
+                                        // We currently support it for dual-named default theme resource
+                                        if (op != null
+                                            && op.Name == TrampolineName)
+                                        {
+                                            foundXamlLoader = true;
+                                            break;
+                                        }
+                                        if (op != null
+                                            && op.Name == "Load"
+                                            && op.Parameters.Count == 1
+                                            && op.Parameters[0].ParameterType.FullName == "System.Object"
+                                            && op.DeclaringType.FullName == "Avalonia.Markup.Xaml.AvaloniaXamlLoader")
+                                        {
+                                            i[c].Operand = trampoline;
+                                            foundXamlLoader = true;
+                                        }
+                                    }
+                                }
+                            }
+
+                            if (!foundXamlLoader)
+                            {
+                                var ctors = classTypeDefinition.GetConstructors()
+                                    .Where(c => !c.IsStatic).ToList();
+                                // We can inject xaml loader into default constructor
+                                if (ctors.Count == 1 && ctors[0].Body.Instructions.Count(o=>o.OpCode != OpCodes.Nop) == 3)
+                                {
+                                    var i = ctors[0].Body.Instructions;
+                                    var retIdx = i.IndexOf(i.Last(x => x.OpCode == OpCodes.Ret));
+                                    i.Insert(retIdx, Instruction.Create(OpCodes.Call, trampoline));
+                                    i.Insert(retIdx, Instruction.Create(OpCodes.Ldarg_0));
+                                }
+                                else
+                                {
+                                    throw new InvalidProgramException(
+                                        $"No call to AvaloniaXamlLoader.Load(this) call found anywhere in the type {classType.FullName} and type seems to have custom constructors.");
+                                }
+                            }
+
+                        }
+
+                        if (buildName != null || classTypeDefinition != null)
+                        {
+                            var compiledBuildMethod = buildName == null ?
+                                null :
+                                typeSystem.GetTypeReference(builder).Resolve()
+                                    .Methods.First(m => m.Name == buildName);
+                            var parameterlessConstructor = compiledBuildMethod != null ?
+                                null :
+                                classTypeDefinition.GetConstructors().FirstOrDefault(c =>
+                                    c.IsPublic && !c.IsStatic && !c.HasParameters);
+
+                            if (compiledBuildMethod != null || parameterlessConstructor != null)
+                            {
+                                var i = loaderDispatcherMethod.Body.Instructions;
+                                var nop = Instruction.Create(OpCodes.Nop);
+                                i.Add(Instruction.Create(OpCodes.Ldarg_0));
+                                i.Add(Instruction.Create(OpCodes.Ldstr, res.Uri));
+                                i.Add(Instruction.Create(OpCodes.Call, stringEquals));
+                                i.Add(Instruction.Create(OpCodes.Brfalse, nop));
+                                if (parameterlessConstructor != null)
+                                    i.Add(Instruction.Create(OpCodes.Newobj, parameterlessConstructor));
+                                else
+                                {
+                                    i.Add(Instruction.Create(OpCodes.Ldsfld, rootServiceProviderField));
+                                    i.Add(Instruction.Create(OpCodes.Call, compiledBuildMethod));
+                                }
+
+                                i.Add(Instruction.Create(OpCodes.Ret));
+                                i.Add(nop);
+                            }
+                        }
+
+                    }
+                    catch (Exception e)
+                    {
+                        int lineNumber = 0, linePosition = 0;
+                        if (e is XamlIlParseException xe)
+                        {
+                            lineNumber = xe.LineNumber;
+                            linePosition = xe.LinePosition;
+                        }
+                        engine.LogErrorEvent(new BuildErrorEventArgs("Avalonia", "XAMLIL", res.FilePath,
+                            lineNumber, linePosition, lineNumber, linePosition,
+                            e.Message, "", "Avalonia"));
+                        return false;
+                    }
+                    res.Remove();
+                }
+                return true;
+            }
+            
+            if (emres.Resources.Count(CheckXamlName) != 0)
+                if (!CompileGroup(emres))
+                    return new CompileResult(false);
+            if (avares.Resources.Count(CheckXamlName) != 0)
+            {
+                if (!CompileGroup(avares))
+                    return new CompileResult(false);
+                avares.Save();
+            }
+            
+            loaderDispatcherMethod.Body.Instructions.Add(Instruction.Create(OpCodes.Ldnull));
+            loaderDispatcherMethod.Body.Instructions.Add(Instruction.Create(OpCodes.Ret));
+            
+            asm.Write(output, new WriterParameters
+            {
+                WriteSymbols = asm.MainModule.HasSymbols
+            });
+
+            return new CompileResult(true, true);
+        }
+        
+    }
+}

+ 5 - 1
src/Avalonia.Controls.DataGrid/Avalonia.Controls.DataGrid.csproj

@@ -1,4 +1,4 @@
-<Project Sdk="Microsoft.NET.Sdk">
+<Project Sdk="Microsoft.NET.Sdk">
   <PropertyGroup>
     <TargetFramework>netstandard2.0</TargetFramework>
   </PropertyGroup>
@@ -11,10 +11,14 @@
     <ProjectReference Include="..\Avalonia.Remote.Protocol\Avalonia.Remote.Protocol.csproj" />
     <ProjectReference Include="..\Avalonia.Visuals\Avalonia.Visuals.csproj" />
     <ProjectReference Include="..\Avalonia.Styling\Avalonia.Styling.csproj" />
+    <ProjectReference Include="..\Markup\Avalonia.Markup.Xaml\Avalonia.Markup.Xaml.csproj" />
     <ProjectReference Include="..\Markup\Avalonia.Markup\Avalonia.Markup.csproj" />    
     <ProjectReference Include="..\Avalonia.Controls\Avalonia.Controls.csproj" />
+    <!-- Compatibility with old apps -->
+    <EmbeddedResource Include="Themes\**\*.xaml"/>
   </ItemGroup>
   <Import Project="..\..\build\Rx.props" />
   <Import Project="..\..\build\EmbedXaml.props" />
   <Import Project="..\..\build\JetBrains.Annotations.props" />
+  <Import Project="..\..\build\BuildTargets.targets" />
 </Project>

+ 1 - 0
src/Avalonia.Controls.DataGrid/DataGridBoundColumn.cs

@@ -26,6 +26,7 @@ namespace Avalonia.Controls
         /// Gets or sets the binding that associates the column with a property in the data source.
         /// </summary>
         //TODO Binding
+        [AssignBinding]
         public virtual IBinding Binding
         {
             get

+ 5 - 3
src/Avalonia.DesignerSupport/Remote/RemoteDesignerEntryPoint.cs

@@ -2,6 +2,7 @@
 using System.Collections.Generic;
 using System.Net;
 using System.Reflection;
+using System.Xml;
 using Avalonia.Controls;
 using Avalonia.Input;
 using Avalonia.Remote.Protocol;
@@ -206,7 +207,8 @@ namespace Avalonia.DesignerSupport.Remote
                 catch (Exception e)
                 {
                     var xamlException = e as XamlException;
-
+                    var xmlException = e as XmlException;
+                    
                     s_transport.Send(new UpdateXamlResultMessage
                     {
                         Error = e.ToString(),
@@ -214,8 +216,8 @@ namespace Avalonia.DesignerSupport.Remote
                         {
                             ExceptionType = e.GetType().FullName,
                             Message = e.Message.ToString(),
-                            LineNumber = xamlException?.LineNumber,
-                            LinePosition = xamlException?.LinePosition,
+                            LineNumber = xamlException?.LineNumber ?? xmlException?.LineNumber,
+                            LinePosition = xamlException?.LinePosition ?? xmlException?.LinePosition,
                         }
                     });
                 }

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

@@ -17,4 +17,5 @@
   </ItemGroup>  
   <Import Project="..\..\build\EmbedXaml.props" />
   <Import Project="..\..\build\Rx.props" />
+  <Import Project="..\..\build\BuildTargets.targets" />
 </Project>

+ 3 - 1
src/Avalonia.Diagnostics/DevTools.xaml

@@ -1,4 +1,6 @@
-<UserControl xmlns="https://github.com/avaloniaui">
+<UserControl xmlns="https://github.com/avaloniaui"
+             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+             x:Class="Avalonia.Diagnostics.DevTools">
   <Grid RowDefinitions="Auto,*,Auto">
     <TabStrip SelectedIndex="{Binding SelectedTab, Mode=TwoWay}">
       <TabStripItem Content="Logical Tree"/>

+ 6 - 0
src/Avalonia.Diagnostics/DevTools.xaml.cs

@@ -43,6 +43,12 @@ namespace Avalonia.Diagnostics
                 .Subscribe(RawKeyDown);
         }
 
+        // HACK: needed for XAMLIL, will fix that later
+        public DevTools()
+        {
+            
+        }
+
         public IControl Root { get; }
 
         public static IDisposable Attach(TopLevel control)

+ 2 - 1
src/Avalonia.Diagnostics/Views/EventsView.xaml

@@ -1,6 +1,7 @@
 <UserControl xmlns="https://github.com/avaloniaui"
              xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
-             xmlns:vm="clr-namespace:Avalonia.Diagnostics.ViewModels">
+             xmlns:vm="clr-namespace:Avalonia.Diagnostics.ViewModels"
+             x:Class="Avalonia.Diagnostics.Views.EventsView">
     <UserControl.Resources>
         <vm:BoolToBrushConverter x:Key="boolToBrush" />
     </UserControl.Resources>

+ 3 - 1
src/Avalonia.Diagnostics/Views/TreePageView.xaml

@@ -1,5 +1,7 @@
 <UserControl xmlns="https://github.com/avaloniaui"
-             xmlns:vm="clr-namespace:Avalonia.Diagnostics.ViewModels">
+             xmlns:vm="clr-namespace:Avalonia.Diagnostics.ViewModels"
+             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+             x:Class="Avalonia.Diagnostics.Views.TreePageView">
   <Grid ColumnDefinitions="*,4,3*">    
     <TreeView Name="tree" Items="{Binding Nodes}" SelectedItem="{Binding SelectedNode, Mode=TwoWay}">
       <TreeView.DataTemplates>

+ 2 - 1
src/Avalonia.Styling/Controls/NameScopeExtensions.cs

@@ -71,10 +71,11 @@ namespace Avalonia.Controls
         {
             Contract.Requires<ArgumentNullException>(control != null);
 
-            return control.GetSelfAndLogicalAncestors()
+            var scope = control.GetSelfAndLogicalAncestors()
                 .OfType<StyledElement>()
                 .Select(x => (x as INameScope) ?? NameScope.GetNameScope(x))
                 .FirstOrDefault(x => x != null);
+            return scope;
         }
     }
 }

+ 11 - 0
src/Avalonia.Styling/Styling/Selectors.cs

@@ -114,6 +114,17 @@ namespace Avalonia.Styling
         {
             return new NotSelector(previous, argument(null));
         }
+        
+        /// <summary>
+        /// Returns a selector which inverts the results of selector argument.
+        /// </summary>
+        /// <param name="previous">The previous selector.</param>
+        /// <param name="argument">The selector to be not-ed.</param>
+        /// <returns>The selector.</returns>
+        public static Selector Not(this Selector previous, Selector argument)
+        {
+            return new NotSelector(previous, argument);
+        }
 
         /// <summary>
         /// Returns a selector which matches a type.

+ 1 - 1
src/Avalonia.Themes.Default/Accents/BaseDark.xaml

@@ -1,6 +1,6 @@
 <Style xmlns="https://github.com/avaloniaui"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
-       xmlns:sys="clr-namespace:System;assembly=mscorlib">
+       xmlns:sys="clr-namespace:System;assembly=netstandard">
     <Style.Resources>
 
         <Color x:Key="ThemeAccentColor">#CC119EDA</Color>

+ 1 - 1
src/Avalonia.Themes.Default/Accents/BaseLight.xaml

@@ -1,6 +1,6 @@
 <Style xmlns="https://github.com/avaloniaui"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
-       xmlns:sys="clr-namespace:System;assembly=mscorlib">
+       xmlns:sys="clr-namespace:System;assembly=netstandard">
     <Style.Resources>
 
         <Color x:Key="ThemeAccentColor">#CC119EDA</Color>

+ 5 - 6
src/Avalonia.Themes.Default/Avalonia.Themes.Default.csproj

@@ -12,13 +12,12 @@
     <ProjectReference Include="..\Avalonia.Layout\Avalonia.Layout.csproj" />
     <ProjectReference Include="..\Avalonia.Visuals\Avalonia.Visuals.csproj" />
     <ProjectReference Include="..\Avalonia.Styling\Avalonia.Styling.csproj" />
-    <AvaloniaResource Include="DefaultTheme.xaml" />
-    <AvaloniaResource Include="Accents/*.xaml" />
+    <AvaloniaResource Include="DefaultTheme.xaml"/>
+    <AvaloniaResource Include="Accents/*.xaml"/>
+    <!-- Compatibility with old apps, probably need to replace with AvaloniaResource -->
+    <EmbeddedResource Include="**/*.xaml"/>
   </ItemGroup>
-  <ItemGroup>
-    <None Remove="NotificationArea.xaml" />
-  </ItemGroup>  
-  <Import Project="..\..\build\EmbedXaml.props" />
+  <Import Project="..\..\build\BuildTargets.targets"/>
   <Import Project="..\..\build\BuildTargets.targets" />
   <Import Project="..\..\build\Rx.props" />
 </Project>

+ 3 - 6
src/Avalonia.Themes.Default/DatePicker.xaml

@@ -7,7 +7,7 @@
 
 <Styles xmlns="https://github.com/avaloniaui"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
-        xmlns:sys="clr-namespace:System;assembly=mscorlib">
+        xmlns:sys="clr-namespace:System;assembly=netstandard">
   <Style Selector="DatePicker">
 
     <Setter Property="Background" Value="{DynamicResource ThemeBackgroundBrush}"/>
@@ -63,11 +63,8 @@
                                Grid.ColumnSpan="4"
                                Grid.RowSpan="3"
                                FontSize="{DynamicResource FontSizeSmall}"
-                               Foreground="{DynamicResource ThemeBorderHighBrush}">
-                               <TextBlock.Text>
-                                 <Binding Source="{x:Static sys:DateTime.Today}" Path="Day"/>
-                               </TextBlock.Text>
-                    </TextBlock>
+                               Foreground="{DynamicResource ThemeBorderHighBrush}"
+                               Text="{Binding Source={x:Static sys:DateTime.Today}, Path=Day}"/>
 
                     <Ellipse HorizontalAlignment="Center" VerticalAlignment="Center" Fill="{DynamicResource ThemeControlLowBrush}" StrokeThickness="0" Grid.ColumnSpan="4" Width="3" Height="3"/>
                   </Grid>

+ 3 - 1
src/Avalonia.Themes.Default/DefaultTheme.xaml

@@ -1,4 +1,6 @@
-<Styles xmlns="https://github.com/avaloniaui">
+<Styles xmlns="https://github.com/avaloniaui"
+        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+        x:Class="Avalonia.Themes.Default.DefaultTheme">
   <!-- Define ToolTip first so its styles can be overriden by other controls (e.g. TextBox) -->
   <StyleInclude Source="resm:Avalonia.Themes.Default.ToolTip.xaml?assembly=Avalonia.Themes.Default"/>
   <StyleInclude Source="resm:Avalonia.Themes.Default.DataValidationErrors.xaml?assembly=Avalonia.Themes.Default"/>

+ 0 - 7
src/Avalonia.Themes.Default/DefaultTheme.xaml.cs

@@ -11,12 +11,5 @@ namespace Avalonia.Themes.Default
     /// </summary>
     public class DefaultTheme : Styles
     {
-        /// <summary>
-        /// Initializes a new instance of the <see cref="DefaultTheme"/> class.
-        /// </summary>
-        public DefaultTheme()
-        {
-            AvaloniaXamlLoader.Load(this);
-        }
     }
 }

+ 1 - 1
src/Avalonia.Themes.Default/MenuItem.xaml

@@ -1,5 +1,5 @@
 <Styles xmlns="https://github.com/avaloniaui"
-        xmlns:sys="clr-namespace:System;assembly=mscorlib">
+        xmlns:sys="clr-namespace:System;assembly=netstandard">
   
   <Style Selector="MenuItem">
     <Setter Property="Background" Value="Transparent"/>

+ 2 - 0
src/Avalonia.Visuals/Visual.cs

@@ -10,6 +10,7 @@ using Avalonia.Data;
 using Avalonia.Logging;
 using Avalonia.LogicalTree;
 using Avalonia.Media;
+using Avalonia.Metadata;
 using Avalonia.Rendering;
 using Avalonia.Utilities;
 using Avalonia.VisualTree;
@@ -25,6 +26,7 @@ namespace Avalonia
     /// <see cref="IRenderer"/> to render the control. To traverse the visual tree, use the
     /// extension methods defined in <see cref="VisualExtensions"/>.
     /// </remarks>
+    [UsableDuringInitialization]
     public class Visual : StyledElement, IVisual
     {
         /// <summary>

+ 31 - 1
src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj

@@ -1,7 +1,9 @@
 <Project Sdk="Microsoft.NET.Sdk">
   <PropertyGroup>
     <TargetFramework>netstandard2.0</TargetFramework>
-    <DefineConstants>PCL;NETSTANDARD;NETSTANDARD2_0;HAS_TYPE_CONVERTER;HAS_CUSTOM_ATTRIBUTE_PROVIDER</DefineConstants>
+    <DefineConstants>PCL;NETSTANDARD;NETSTANDARD2_0;HAS_TYPE_CONVERTER;HAS_CUSTOM_ATTRIBUTE_PROVIDER;XAMLIL_INTERNAL</DefineConstants>
+    <UseCecil>false</UseCecil>
+    <DefineConstants Condition="$(UseCecil) == true">$(DefineConstants);RUNTIME_XAML_CECIL</DefineConstants>
     <EnableDefaultCompileItems>False</EnableDefaultCompileItems>
     <EnableDefaultItems>false</EnableDefaultItems>
     <NoWarn>CS1591</NoWarn>
@@ -16,6 +18,7 @@
         <Compile Include="Converters\ParseTypeConverter.cs" />
         <Compile Include="Converters\SetterValueTypeConverter.cs" />
         <Compile Include="Converters\TimeSpanTypeConverter.cs" />
+        <Compile Include="Extensions.cs" />
         <Compile Include="MarkupExtensions\DynamicResourceExtension.cs" />
         <Compile Include="MarkupExtensions\ResourceInclude.cs" />
         <Compile Include="MarkupExtensions\StaticResourceExtension.cs" />
@@ -51,8 +54,33 @@
         <Compile Include="Templates\TemplateContent.cs" />
         <Compile Include="Templates\TemplateLoader.cs" />
         <Compile Include="Templates\TreeDataTemplate.cs" />
+        <Compile Include="XamlIl\AvaloniaXamlIlRuntimeCompiler.cs" />
+        <Compile Include="XamlIl\CompilerExtensions\Transformers\AvaloniaBindingExtensionHackTransformer.cs" />
+        <Compile Include="XamlIl\CompilerExtensions\Transformers\AvaloniaXamlIlAvaloniaPropertyResolver.cs" />
+        <Compile Include="XamlIl\CompilerExtensions\Transformers\AvaloniaXamlIlConstructorServiceProviderTransformer.cs" />
+        <Compile Include="XamlIl\CompilerExtensions\Transformers\AvaloniaXamlIlControlTemplateTargetTypeMetadataTransformer.cs" />
+        <Compile Include="XamlIl\CompilerExtensions\Transformers\AvaloniaXamlIlDesignPropertiesTransformer.cs" />
+        <Compile Include="XamlIl\CompilerExtensions\Transformers\AvaloniaXamlIlMetadataRemover.cs" />
+        <Compile Include="XamlIl\CompilerExtensions\Transformers\AvaloniaXamlIlTransformInstanceAttachedProperties.cs" />
+        <Compile Include="XamlIl\CompilerExtensions\Transformers\AvaloniaXamlIlTransitionsTypeMetadataTransformer.cs" />
+        <Compile Include="XamlIl\CompilerExtensions\Transformers\AvaloniaXamlIlWellKnownTypes.cs" />
+        <Compile Include="XamlIl\CompilerExtensions\XamlIlAvaloniaPropertyHelper.cs" />
+        <Compile Include="XamlIl\CompilerExtensions\AvaloniaXamlIlCompiler.cs" />
+        <Compile Include="XamlIl\CompilerExtensions\AvaloniaXamlIlLanguage.cs" />
+        <Compile Include="XamlIl\CompilerExtensions\Transformers\AddNameScopeRegistration.cs" />
+        <Compile Include="XamlIl\CompilerExtensions\Transformers\AvaloniaXamlIlSetterTransformer.cs" />
+        <Compile Include="XamlIl\CompilerExtensions\Transformers\IgnoredDirectivesTransformer.cs" />
+        <Compile Include="XamlIl\CompilerExtensions\Transformers\AvaloniaXamlIlSelectorTransformer.cs" />
+        <Compile Include="XamlIl\CompilerExtensions\Transformers\XNameTransformer.cs" />
+        <Compile Include="XamlIl\Runtime\IAvaloniaXamlIlParentStackProvider.cs" />
+        <Compile Include="XamlIl\Runtime\IAvaloniaXamlIlXmlNamespaceInfoProviderV1.cs" />
+        <Compile Include="XamlIl\Runtime\XamlIlRuntimeHelpers.cs" />
         <Compile Include="XamlLoadException.cs" />
         <Compile Include="PortableXaml\portable.xaml.github\src\Portable.Xaml\**\*.cs" Exclude="PortableXaml\portable.xaml.github\src\Portable.Xaml\Assembly\**\*.cs" />
+        <Compile Include="XamlIl\xamlil.github\src\XamlIl\**\*.cs" />
+        <Compile Condition="$(UseCecil) == true" Include="XamlIl\xamlil.github\src\XamlIl.Cecil\**\*.cs" />
+        <Compile Remove="XamlIl\xamlil.github\**\obj\**\*.cs" />
+        <Compile Include="..\Avalonia.Markup\Markup\Parsers\SelectorGrammar.cs" />
     </ItemGroup>
   <ItemGroup>
     <ProjectReference Include="..\..\Avalonia.Animation\Avalonia.Animation.csproj" />
@@ -64,6 +92,8 @@
     <ProjectReference Include="..\..\Avalonia.Visuals\Avalonia.Visuals.csproj" />
     <ProjectReference Include="..\..\Avalonia.Styling\Avalonia.Styling.csproj" />
     <ProjectReference Include="..\Avalonia.Markup\Avalonia.Markup.csproj" />
+    <PackageReference Include="System.Reflection.Emit" Version="4.3.0" />
+    <PackageReference Condition="$(UseCecil) == true" Include="Mono.Cecil" Version="0.10.3" />
   </ItemGroup>
   <Import Project="..\..\..\build\Rx.props" />
 </Project>

+ 1 - 0
src/Markup/Avalonia.Markup.Xaml/AvaloniaTypeConverters.cs

@@ -30,6 +30,7 @@ namespace Avalonia.Markup.Xaml
     /// </remarks>
     public static class AvaloniaTypeConverters
     {
+        // When adding item to that list make sure to modify AvaloniaXamlIlLanguage
         private static Dictionary<Type, Type> _converters = new Dictionary<Type, Type>()
         {
             { typeof(AvaloniaList<>), typeof(AvaloniaListConverter<>) },

+ 24 - 11
src/Markup/Avalonia.Markup.Xaml/AvaloniaXamlLoader.cs

@@ -10,6 +10,7 @@ using System.Reflection;
 using System.Runtime.Serialization;
 using System.Text;
 using System.Xml.Linq;
+using Avalonia.Markup.Xaml.XamlIl;
 using Avalonia.Controls;
 using Avalonia.Markup.Data;
 using Avalonia.Markup.Xaml.PortableXaml;
@@ -25,6 +26,8 @@ namespace Avalonia.Markup.Xaml
     {
         public bool IsDesignMode { get; set; }
 
+        public static bool UseLegacyXamlLoader { get; set; } = false;
+        
         /// <summary>
         /// Initializes a new instance of the <see cref="AvaloniaXamlLoader"/> class.
         /// </summary>
@@ -65,8 +68,8 @@ namespace Avalonia.Markup.Xaml
             {
                 throw new InvalidOperationException(
                     "Could not create IAssetLoader : maybe Application.RegisterServices() wasn't called?");
-            }
-
+            }           
+            
             foreach (var uri in GetUrisFor(assetLocator, type))
             {
                 if (assetLocator.Exists(uri))
@@ -113,21 +116,27 @@ namespace Avalonia.Markup.Xaml
                     "Could not create IAssetLoader : maybe Application.RegisterServices() wasn't called?");
             }
 
+            var compiledLoader = assetLocator.GetAssembly(uri, baseUri)
+                ?.GetType("CompiledAvaloniaXaml.!XamlLoader")
+                ?.GetMethod("TryLoad", new[] {typeof(string)});
+            if (compiledLoader != null)
+            {
+                var uriString = (!uri.IsAbsoluteUri && baseUri != null ? new Uri(baseUri, uri) : uri)
+                    .ToString();
+                var compiledResult = compiledLoader.Invoke(null, new object[] {uriString});
+                if (compiledResult != null)
+                    return compiledResult;
+            }
+            
+            
             var asset = assetLocator.OpenAndGetAssembly(uri, baseUri);
             using (var stream = asset.stream)
             {
                 var absoluteUri = uri.IsAbsoluteUri ? uri : new Uri(baseUri, uri);
-                try
-                {
-                    return Load(stream, asset.assembly, rootInstance, absoluteUri);
-                }
-                catch (Exception e)
-                {
-                    throw new XamlLoadException("Error loading xaml at " + absoluteUri + ": " + e.Message, e);
-                }
+                return Load(stream, asset.assembly, rootInstance, absoluteUri);
             }
         }
-
+        
         /// <summary>
         /// Loads XAML from a string.
         /// </summary>
@@ -159,6 +168,10 @@ namespace Avalonia.Markup.Xaml
         /// <returns>The loaded object.</returns>
         public object Load(Stream stream, Assembly localAssembly, object rootInstance = null, Uri uri = null)
         {
+            if (!UseLegacyXamlLoader)
+                return AvaloniaXamlIlRuntimeCompiler.Load(stream, localAssembly, rootInstance, uri, IsDesignMode);
+
+
             var readerSettings = new XamlXmlReaderSettings()
             {
                 BaseUri = uri,

+ 2 - 2
src/Markup/Avalonia.Markup.Xaml/Converters/AvaloniaPropertyTypeConverter.cs

@@ -28,8 +28,8 @@ namespace Avalonia.Markup.Xaml.Converters
             var parser = new PropertyParser();
             var (ns, owner, propertyName) = parser.Parse(new CharacterReader(((string)value).AsSpan()));
             var ownerType = TryResolveOwnerByName(context, ns, owner);
-            var targetType = context.GetFirstAmbientValue<ControlTemplate>()?.TargetType ??
-                context.GetFirstAmbientValue<Style>()?.Selector?.TargetType ??
+            var targetType = context.GetFirstParent<ControlTemplate>()?.TargetType ??
+                context.GetFirstParent<Style>()?.Selector?.TargetType ??
                 typeof(Control);
             var effectiveOwner = ownerType ?? targetType;
             var property = registry.FindRegistered(effectiveOwner, propertyName);

+ 4 - 3
src/Markup/Avalonia.Markup.Xaml/Converters/AvaloniaUriTypeConverter.cs

@@ -17,9 +17,10 @@ namespace Avalonia.Markup.Xaml.Converters
             if (s == null)
                 return null;
             //On Unix Uri tries to interpret paths starting with "/" as file Uris
-            if (s.StartsWith("/"))
-                return new Uri(s, UriKind.Relative);
-            return new Uri(s);
+            var kind = s.StartsWith("/") ? UriKind.Relative : UriKind.Absolute;
+            if (!Uri.TryCreate(s, kind, out var res))
+                throw new ArgumentException("Unable to parse URI: " + s);
+            return res;
         }
     }
 }

+ 2 - 2
src/Markup/Avalonia.Markup.Xaml/Converters/BitmapTypeConverter.cs

@@ -29,7 +29,7 @@ namespace Avalonia.Markup.Xaml.Converters
                 return new Bitmap(uri.LocalPath);
 
             var assets = AvaloniaLocator.Current.GetService<IAssetLoader>();
-            return new Bitmap(assets.Open(uri, context.GetBaseUri()));
+            return new Bitmap(assets.Open(uri, context.GetContextBaseUri()));
         }
     }
-}
+}

+ 1 - 1
src/Markup/Avalonia.Markup.Xaml/Converters/FontFamilyTypeConverter.cs

@@ -22,7 +22,7 @@ namespace Avalonia.Markup.Xaml.Converters
         {
             var s = (string)value;
 
-            return FontFamily.Parse(s, context.GetBaseUri());
+            return FontFamily.Parse(s, context.GetContextBaseUri());
         }
     }
 }

+ 1 - 1
src/Markup/Avalonia.Markup.Xaml/Converters/IconTypeConverter.cs

@@ -45,7 +45,7 @@ namespace Avalonia.Markup.Xaml.Converters
             if(uri.IsAbsoluteUri && uri.IsFile)
                 return new WindowIcon(uri.LocalPath);
             var assets = AvaloniaLocator.Current.GetService<IAssetLoader>();
-            return new WindowIcon(assets.Open(uri, context.GetBaseUri()));
+            return new WindowIcon(assets.Open(uri, context.GetContextBaseUri()));
         }
     }
 }

+ 61 - 0
src/Markup/Avalonia.Markup.Xaml/Extensions.cs

@@ -0,0 +1,61 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Linq;
+using Avalonia.Markup.Xaml.XamlIl.Runtime;
+using Portable.Xaml;
+using Portable.Xaml.Markup;
+
+namespace Avalonia.Markup.Xaml
+{
+    internal static class Extensions
+    {
+        public static T GetService<T>(this IServiceProvider sp) => (T)sp?.GetService(typeof(T));
+        
+        
+        public static Uri GetContextBaseUri(this IServiceProvider ctx)
+        {
+            var properService = ctx.GetService<IUriContext>();
+            if (properService != null)
+                return properService.BaseUri;
+            // Ugly hack with casts
+            return Portable.Xaml.ComponentModel.TypeDescriptorExtensions.GetBaseUri((ITypeDescriptorContext)ctx);
+        }
+
+        public static T GetFirstParent<T>(this IServiceProvider ctx) where T : class
+        {
+            var parentStack = ctx.GetService<IAvaloniaXamlIlParentStackProvider>();
+            if (parentStack != null)
+                return parentStack.Parents.OfType<T>().FirstOrDefault();
+            return Portable.Xaml.ComponentModel.TypeDescriptorExtensions.GetFirstAmbientValue<T>((ITypeDescriptorContext)ctx);
+        }
+        
+        public static T GetLastParent<T>(this IServiceProvider ctx) where T : class
+        {
+            var parentStack = ctx.GetService<IAvaloniaXamlIlParentStackProvider>();
+            if (parentStack != null)
+                return parentStack.Parents.OfType<T>().LastOrDefault();
+            return Portable.Xaml.ComponentModel.TypeDescriptorExtensions.GetLastOrDefaultAmbientValue<T>(
+                (ITypeDescriptorContext)ctx);
+        }
+
+        public static IEnumerable<T> GetParents<T>(this IServiceProvider sp)
+        {
+            var stack = sp.GetService<IAvaloniaXamlIlParentStackProvider>();
+            if (stack != null)
+                return stack.Parents.OfType<T>();
+            
+            var context = (ITypeDescriptorContext)sp;
+            var schemaContext = context.GetService<IXamlSchemaContextProvider>().SchemaContext;
+            var ambientProvider = context.GetService<IAmbientProvider>();
+            return ambientProvider.GetAllAmbientValues(schemaContext.GetXamlType(typeof(T))).OfType<T>();
+        }
+
+        public static Type ResolveType(this IServiceProvider ctx, string namespacePrefix, string type)
+        {
+            var tr = ctx.GetService<IXamlTypeResolver>();
+            string name = string.IsNullOrEmpty(namespacePrefix) ? type : $"{namespacePrefix}:{type}";
+            return tr?.Resolve(name);
+        }
+    }
+}

+ 8 - 3
src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/BindingExtension.cs

@@ -29,6 +29,11 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions
         }
 
         public override object ProvideValue(IServiceProvider serviceProvider)
+        {
+            return ProvideTypedValue(serviceProvider);
+        }
+        
+        public Binding ProvideTypedValue(IServiceProvider serviceProvider)
         {
             var descriptorContext = (ITypeDescriptorContext)serviceProvider;
 
@@ -49,18 +54,18 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions
             };
         }
 
-        private static object GetDefaultAnchor(ITypeDescriptorContext context)
+        private static object GetDefaultAnchor(IServiceProvider context)
         {
             // If the target is not a control, so we need to find an anchor that will let us look
             // up named controls and style resources. First look for the closest IControl in
             // the context.
-            object anchor = context.GetFirstAmbientValue<IControl>();
+            object anchor = context.GetFirstParent<IControl>();
 
             // If a control was not found, then try to find the highest-level style as the XAML
             // file could be a XAML file containing only styles.
             return anchor ??
                     context.GetService<IRootObjectProvider>()?.RootObject as IStyle ??
-                    context.GetLastOrDefaultAmbientValue<IStyle>();
+                    context.GetLastParent<IStyle>();
         }
 
         public IValueConverter Converter { get; set; }

+ 5 - 15
src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/DynamicResourceExtension.cs

@@ -28,14 +28,15 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions
 
         public string ResourceKey { get; set; }
 
-        public override object ProvideValue(IServiceProvider serviceProvider)
+        public override object ProvideValue(IServiceProvider serviceProvider) => ProvideTypedValue(serviceProvider);
+        
+        public IBinding ProvideTypedValue(IServiceProvider serviceProvider)
         {
-            var context = (ITypeDescriptorContext)serviceProvider;
-            var provideTarget = context.GetService<IProvideValueTarget>();
+            var provideTarget = serviceProvider.GetService<IProvideValueTarget>();
 
             if (!(provideTarget.TargetObject is IResourceNode))
             {
-                _anchor = GetAnchor<IResourceNode>(context);
+                _anchor = serviceProvider.GetFirstParent<IResourceNode>();
             }
 
             return this;
@@ -56,16 +57,5 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions
 
             return null;
         }
-
-        private T GetAnchor<T>(ITypeDescriptorContext context) where T : class
-        {
-            var schemaContext = context.GetService<IXamlSchemaContextProvider>().SchemaContext;
-            var ambientProvider = context.GetService<IAmbientProvider>();
-            var xamlType = schemaContext.GetXamlType(typeof(T));
-
-            // We override XamlType.CanAssignTo in BindingXamlType so the results we get back
-            // from GetAllAmbientValues aren't necessarily of the correct type.
-            return ambientProvider.GetAllAmbientValues(xamlType).OfType<T>().FirstOrDefault();
-        }
     }
 }

+ 6 - 1
src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/ResourceInclude.cs

@@ -54,9 +54,14 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions
 
         /// <inhertidoc/>
         public override object ProvideValue(IServiceProvider serviceProvider)
+        {
+            return ProvideTypedValue(serviceProvider);
+        }
+        
+        public ResourceInclude ProvideTypedValue(IServiceProvider serviceProvider)
         {
             var tdc = (ITypeDescriptorContext)serviceProvider;
-            _baseUri = tdc?.GetBaseUri();
+            _baseUri = tdc?.GetContextBaseUri();
             return this;
         }
     }

+ 15 - 19
src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/StaticResourceExtension.cs

@@ -28,36 +28,32 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions
 
         public override object ProvideValue(IServiceProvider serviceProvider)
         {
-            var context = (ITypeDescriptorContext)serviceProvider;
-            var schemaContext = context.GetService<IXamlSchemaContextProvider>().SchemaContext;
-            var ambientProvider = context.GetService<IAmbientProvider>();
-            var resourceProviderType = schemaContext.GetXamlType(typeof(IResourceNode));
-            var ambientValues = ambientProvider.GetAllAmbientValues(resourceProviderType);
+
 
             // Look upwards though the ambient context for IResourceProviders which might be able
             // to give us the resource.
-            foreach (var ambientValue in ambientValues)
+            foreach (var resourceProvider in serviceProvider.GetParents<IResourceNode>())
             {
                 // We override XamlType.CanAssignTo in BindingXamlType so the results we get back
                 // from GetAllAmbientValues aren't necessarily of the correct type.
-                if (ambientValue is IResourceNode resourceProvider)
+
+                if (AvaloniaXamlLoader.UseLegacyXamlLoader 
+                    && resourceProvider is IControl control && control.StylingParent != null)
                 {
-                    if (resourceProvider is IControl control && control.StylingParent != null)
-                    {
-                        // If we've got to a control that has a StylingParent then it's probably
-                        // a top level control and its StylingParent is pointing to the global
-                        // styles. If this is case just do a FindResource on it.
-                        return control.FindResource(ResourceKey);
-                    }
-                    else if (resourceProvider.TryGetResource(ResourceKey, out var value))
-                    {
-                        return value;
-                    }
+                    // If we've got to a control that has a StylingParent then it's probably
+                    // a top level control and its StylingParent is pointing to the global
+                    // styles. If this is case just do a FindResource on it.
+                    return control.FindResource(ResourceKey);
                 }
+                else if (resourceProvider.TryGetResource(ResourceKey, out var value))
+                {
+                    return value;
+                }
+
             }
 
             // The resource still hasn't been found, so add a delayed one-time binding.
-            var provideTarget = context.GetService<IProvideValueTarget>();
+            var provideTarget = serviceProvider.GetService<IProvideValueTarget>();
 
             if (provideTarget.TargetObject is IControl target &&
                 provideTarget.TargetProperty is PropertyInfo property)

+ 4 - 4
src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/StyleIncludeExtension.cs

@@ -18,13 +18,13 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions
         {
         }
 
-        public override object ProvideValue(IServiceProvider serviceProvider)
+        public override object ProvideValue(IServiceProvider serviceProvider) => ProvideTypedValue(serviceProvider);
+        public IStyle ProvideTypedValue(IServiceProvider serviceProvider)
         {
-            var tdc = (ITypeDescriptorContext)serviceProvider;
-            return new StyleInclude(tdc.GetBaseUri()) { Source = Source };
+            return new StyleInclude(serviceProvider.GetContextBaseUri()) { Source = Source };
         }
 
         public Uri Source { get; set; }
 
     }
-}
+}

+ 2 - 2
src/Markup/Avalonia.Markup.Xaml/PortableXaml/TypeDescriptorExtensions.cs

@@ -44,7 +44,7 @@ namespace Portable.Xaml.ComponentModel
             var amb = ctx.GetService<IAmbientProvider>();
             var sc = ctx.GetService<IXamlSchemaContextProvider>().SchemaContext;
 
-            // Because GetFirstAmbientValue uses XamlType.CanAssignTo it returns values that
+            // Because GetFirstParent uses XamlType.CanAssignTo it returns values that
             // aren't actually of the correct type. Use GetAllAmbientValues instead.
             return amb.GetAllAmbientValues(sc.GetXamlType(typeof(T))).OfType<T>().FirstOrDefault();
         }
@@ -98,4 +98,4 @@ namespace Portable.Xaml.ComponentModel
             public AvaloniaXamlContext Context { get; }
         }
     }
-}
+}

+ 5 - 0
src/Markup/Avalonia.Markup.Xaml/Styling/StyleInclude.cs

@@ -25,6 +25,11 @@ namespace Avalonia.Markup.Xaml.Styling
             _baseUri = baseUri;
         }
 
+        public StyleInclude(IServiceProvider serviceProvider)
+        {
+            _baseUri = serviceProvider.GetContextBaseUri();
+        }
+        
         /// <inheritdoc/>
         public event EventHandler<ResourcesChangedEventArgs> ResourcesChanged
         {

+ 6 - 1
src/Markup/Avalonia.Markup.Xaml/Templates/TemplateContent.cs

@@ -1,6 +1,7 @@
 // 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 Avalonia.Controls;
 using System.Collections.Generic;
 
@@ -37,7 +38,11 @@ namespace Avalonia.Markup.Xaml.Templates
 
         public static IControl Load(object templateContent)
         {
+            if (templateContent is Func<IServiceProvider, object> direct)
+            {
+                return (IControl)direct(null);
+            }
             return ((TemplateContent)templateContent).Load();
         }
     }
-}
+}

+ 276 - 0
src/Markup/Avalonia.Markup.Xaml/XamlIl/AvaloniaXamlIlRuntimeCompiler.cs

@@ -0,0 +1,276 @@
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.IO;
+using System.Linq;
+using System.Linq.Expressions;
+using System.Reflection;
+using System.Reflection.Emit;
+using System.Runtime.InteropServices;
+using Avalonia.Markup.Xaml.XamlIl.CompilerExtensions;
+using Avalonia.Markup.Xaml.XamlIl.Runtime;
+using Avalonia.Platform;
+using XamlIl.Transform;
+using XamlIl.TypeSystem;
+#if RUNTIME_XAML_CECIL
+using TypeAttributes = Mono.Cecil.TypeAttributes;
+using Mono.Cecil;
+using XamlIl.Ast;
+#endif
+namespace Avalonia.Markup.Xaml.XamlIl
+{
+    static class AvaloniaXamlIlRuntimeCompiler
+    {
+#if !RUNTIME_XAML_CECIL
+        private static SreTypeSystem _sreTypeSystem;
+        private static ModuleBuilder _sreBuilder;
+        private static IXamlIlType _sreContextType; 
+        private static XamlIlLanguageTypeMappings _sreMappings;
+        private static XamlIlXmlnsMappings _sreXmlns;
+        private static AssemblyBuilder _sreAsm;
+        private static bool _sreCanSave;
+
+        public static void DumpRuntimeCompilationResults()
+        {
+            if (_sreBuilder == null)
+                return;
+            var saveMethod = _sreAsm.GetType().GetMethods()
+                .FirstOrDefault(m => m.Name == "Save" && m.GetParameters().Length == 1);
+            if (saveMethod == null)
+                return;
+            try
+            {
+                _sreBuilder.CreateGlobalFunctions();
+                saveMethod.Invoke(_sreAsm, new Object[] {"XamlIlLoader.ildump"});
+            }
+            catch
+            {
+                //Ignore
+            }
+        }
+        
+        static void InitializeSre()
+        {
+            if (_sreTypeSystem == null)
+                _sreTypeSystem = new SreTypeSystem();
+            if (_sreBuilder == null)
+            {
+                _sreCanSave = !(RuntimeInformation.FrameworkDescription.StartsWith(".NET Core"));
+                var name = new AssemblyName(Guid.NewGuid().ToString("N"));
+                if (_sreCanSave)
+                {
+                    var define = AppDomain.CurrentDomain.GetType().GetMethods()
+                        .FirstOrDefault(m => m.Name == "DefineDynamicAssembly"
+                                    && m.GetParameters().Length == 3 &&
+                                    m.GetParameters()[2].ParameterType == typeof(string));
+                    if (define != null)
+                        _sreAsm = (AssemblyBuilder)define.Invoke(AppDomain.CurrentDomain, new object[]
+                        {
+                            name, (AssemblyBuilderAccess)3,
+                            Path.GetDirectoryName(typeof(AvaloniaXamlIlRuntimeCompiler).Assembly.GetModules()[0]
+                                .FullyQualifiedName)
+                        });
+                    else
+                        _sreCanSave = false;
+                }
+                
+                if(_sreAsm == null)
+                    _sreAsm = AssemblyBuilder.DefineDynamicAssembly(name,
+                        AssemblyBuilderAccess.RunAndCollect);
+                
+                _sreBuilder = _sreAsm.DefineDynamicModule("XamlIlLoader.ildump");
+            }
+
+            if (_sreMappings == null)
+                _sreMappings = AvaloniaXamlIlLanguage.Configure(_sreTypeSystem);
+            if (_sreXmlns == null)
+                _sreXmlns = XamlIlXmlnsMappings.Resolve(_sreTypeSystem, _sreMappings);
+            if (_sreContextType == null)
+                _sreContextType = XamlIlContextDefinition.GenerateContextClass(
+                    _sreTypeSystem.CreateTypeBuilder(
+                        _sreBuilder.DefineType("XamlIlContext")), _sreTypeSystem, _sreMappings);
+        }
+
+
+        static object LoadSre(string xaml, Assembly localAssembly, object rootInstance, Uri uri, bool isDesignMode)
+        {
+            var success = false;
+            try
+            {
+                var rv = LoadSreCore(xaml, localAssembly, rootInstance, uri, isDesignMode);
+                success = true;
+                return rv;
+            }
+            finally
+            {
+                if(!success && _sreCanSave)
+                    DumpRuntimeCompilationResults();
+            }
+        }
+
+        
+        static object LoadSreCore(string xaml, Assembly localAssembly, object rootInstance, Uri uri, bool isDesignMode)
+        {
+
+            InitializeSre();
+            var asm = localAssembly == null ? null : _sreTypeSystem.GetAssembly(localAssembly);
+            
+            var compiler = new AvaloniaXamlIlCompiler(new XamlIlTransformerConfiguration(_sreTypeSystem, asm,
+                _sreMappings, _sreXmlns, AvaloniaXamlIlLanguage.CustomValueConverter),
+                _sreContextType);
+            var tb = _sreBuilder.DefineType("Builder_" + Guid.NewGuid().ToString("N") + "_" + uri);
+
+            IXamlIlType overrideType = null;
+            if (rootInstance != null)
+            {
+                overrideType = _sreTypeSystem.GetType(rootInstance.GetType());
+            }
+
+            compiler.IsDesignMode = isDesignMode;
+            compiler.ParseAndCompile(xaml, uri?.ToString(), null, _sreTypeSystem.CreateTypeBuilder(tb), overrideType);
+            var created = tb.CreateTypeInfo();
+
+            return LoadOrPopulate(created, rootInstance);
+        }
+#endif
+        
+        static object LoadOrPopulate(Type created, object rootInstance)
+        {
+            var isp = Expression.Parameter(typeof(IServiceProvider));
+
+
+            var epar = Expression.Parameter(typeof(object));
+            var populate = created.GetMethod(AvaloniaXamlIlCompiler.PopulateName);
+            isp = Expression.Parameter(typeof(IServiceProvider));
+            var populateCb = Expression.Lambda<Action<IServiceProvider, object>>(
+                Expression.Call(populate, isp, Expression.Convert(epar, populate.GetParameters()[1].ParameterType)),
+                isp, epar).Compile();
+            
+            if (rootInstance == null)
+            {
+                var targetType = populate.GetParameters()[1].ParameterType;
+                var overrideField = targetType.GetField("!XamlIlPopulateOverride",
+                    BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public);
+
+                if (overrideField != null)
+                {
+                    overrideField.SetValue(null,
+                        new Action<object>(
+                            target => { populateCb(XamlIlRuntimeHelpers.RootServiceProviderV1, target); }));
+                    try
+                    {
+                        return Activator.CreateInstance(targetType);
+                    }
+                    finally
+                    {
+                        overrideField.SetValue(null, null);
+                    }
+                }
+                
+                var createCb = Expression.Lambda<Func<IServiceProvider, object>>(
+                    Expression.Convert(Expression.Call(
+                        created.GetMethod(AvaloniaXamlIlCompiler.BuildName), isp), typeof(object)), isp).Compile();
+                return createCb(XamlIlRuntimeHelpers.RootServiceProviderV1);
+            }
+            else
+            {
+                populateCb(XamlIlRuntimeHelpers.RootServiceProviderV1, rootInstance);
+                return rootInstance;
+            }
+        }
+        
+        public static object Load(Stream stream, Assembly localAssembly, object rootInstance, Uri uri,
+            bool isDesignMode)
+        {
+            string xaml;
+            using (var sr = new StreamReader(stream))
+                xaml = sr.ReadToEnd();
+#if RUNTIME_XAML_CECIL
+            return LoadCecil(xaml, localAssembly, rootInstance, uri);
+#else
+            return LoadSre(xaml, localAssembly, rootInstance, uri, isDesignMode);
+#endif
+        }
+
+#if RUNTIME_XAML_CECIL
+        private static Dictionary<string, (Action<IServiceProvider, object> populate, Func<IServiceProvider, object>
+                build)>
+            s_CecilCache =
+                new Dictionary<string, (Action<IServiceProvider, object> populate, Func<IServiceProvider, object> build)
+                >();
+
+
+        private static string _cecilEmitDir;
+        private static CecilTypeSystem _cecilTypeSystem;
+        private static XamlIlLanguageTypeMappings _cecilMappings;
+        private static XamlIlXmlnsMappings _cecilXmlns;
+        private static bool _cecilInitialized;
+
+        static void InitializeCecil()
+        {
+            if(_cecilInitialized)
+                return;
+            var path = Assembly.GetEntryAssembly().GetModules()[0].FullyQualifiedName;
+            _cecilEmitDir = Path.Combine(Path.GetDirectoryName(path), "emit");
+            Directory.CreateDirectory(_cecilEmitDir);
+            var refs = new[] {path}.Concat(File.ReadAllLines(path + ".refs"));
+            _cecilTypeSystem = new CecilTypeSystem(refs);
+            _cecilMappings = AvaloniaXamlIlLanguage.Configure(_cecilTypeSystem);
+            _cecilXmlns = XamlIlXmlnsMappings.Resolve(_cecilTypeSystem, _cecilMappings);
+            _cecilInitialized = true;
+        }
+
+        private static Dictionary<string, Type> _cecilGeneratedCache = new Dictionary<string, Type>();
+        static object LoadCecil(string xaml, Assembly localAssembly, object rootInstance, Uri uri)
+        {
+            if (uri == null)
+                throw new InvalidOperationException("Please, go away");
+            InitializeCecil();
+                        IXamlIlType overrideType = null;
+            if (rootInstance != null)
+            {
+                overrideType = _cecilTypeSystem.GetType(rootInstance.GetType().FullName);
+            }
+
+            
+           
+            var safeUri = uri.ToString()
+                .Replace(":", "_")
+                .Replace("/", "_")
+                .Replace("?", "_")
+                .Replace("=", "_")
+                .Replace(".", "_");
+            if (_cecilGeneratedCache.TryGetValue(safeUri, out var cached))
+                return LoadOrPopulate(cached, rootInstance);
+            
+            
+            var asm = _cecilTypeSystem.CreateAndRegisterAssembly(safeUri, new Version(1, 0),
+                ModuleKind.Dll);            
+            var def = new TypeDefinition("XamlIlLoader", safeUri,
+                TypeAttributes.Class | TypeAttributes.Public, asm.MainModule.TypeSystem.Object);
+
+            var contextDef = new TypeDefinition("XamlIlLoader", safeUri + "_XamlIlContext",
+                TypeAttributes.Class | TypeAttributes.Public, asm.MainModule.TypeSystem.Object);
+            
+            asm.MainModule.Types.Add(def);
+            asm.MainModule.Types.Add(contextDef);
+            
+            var tb = _cecilTypeSystem.CreateTypeBuilder(def);
+
+            var compiler = new AvaloniaXamlIlCompiler(new XamlIlTransformerConfiguration(_cecilTypeSystem,
+                    localAssembly == null ? null : _cecilTypeSystem.FindAssembly(localAssembly.GetName().Name),
+                    _cecilMappings, XamlIlXmlnsMappings.Resolve(_cecilTypeSystem, _cecilMappings),
+                    AvaloniaXamlIlLanguage.CustomValueConverter),
+                _cecilTypeSystem.CreateTypeBuilder(contextDef));
+            compiler.ParseAndCompile(xaml, uri.ToString(), tb, overrideType);
+            var asmPath = Path.Combine(_cecilEmitDir, safeUri + ".dll");
+            using(var f = File.Create(asmPath))
+                asm.Write(f);
+            var loaded = Assembly.LoadFile(asmPath)
+                .GetTypes().First(x => x.Name == safeUri);
+            _cecilGeneratedCache[safeUri] = loaded;
+            return LoadOrPopulate(loaded, rootInstance);
+        }
+#endif
+    }
+}

+ 124 - 0
src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/AvaloniaXamlIlCompiler.cs

@@ -0,0 +1,124 @@
+using System.Collections.Generic;
+using System.Linq;
+using Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers;
+using XamlIl;
+using XamlIl.Ast;
+using XamlIl.Parsers;
+using XamlIl.Transform;
+using XamlIl.Transform.Transformers;
+using XamlIl.TypeSystem;
+
+namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
+{
+    class AvaloniaXamlIlCompiler : XamlIlCompiler
+    {
+        private readonly XamlIlTransformerConfiguration _configuration;
+        private readonly IXamlIlType _contextType;
+        private readonly AvaloniaXamlIlDesignPropertiesTransformer _designTransformer;
+
+        private AvaloniaXamlIlCompiler(XamlIlTransformerConfiguration configuration) : base(configuration, true)
+        {
+            _configuration = configuration;
+
+            void InsertAfter<T>(params IXamlIlAstTransformer[] t) 
+                => Transformers.InsertRange(Transformers.FindIndex(x => x is T) + 1, t);
+
+            void InsertBefore<T>(params IXamlIlAstTransformer[] t) 
+                => Transformers.InsertRange(Transformers.FindIndex(x => x is T), t);
+
+
+            // Before everything else
+            
+            Transformers.Insert(0, new XNameTransformer());
+            Transformers.Insert(1, new IgnoredDirectivesTransformer());
+            Transformers.Insert(2, _designTransformer = new AvaloniaXamlIlDesignPropertiesTransformer());
+            Transformers.Insert(3, new AvaloniaBindingExtensionHackTransformer());
+            
+            
+            // Targeted
+
+            InsertBefore<XamlIlPropertyReferenceResolver>(new AvaloniaXamlIlTransformInstanceAttachedProperties());
+            InsertAfter<XamlIlPropertyReferenceResolver>(new AvaloniaXamlIlAvaloniaPropertyResolver());
+            
+
+
+            InsertBefore<XamlIlContentConvertTransformer>(
+                new AvaloniaXamlIlSelectorTransformer(),
+                new AvaloniaXamlIlSetterTransformer(),
+                new AvaloniaXamlIlControlTemplateTargetTypeMetadataTransformer(),
+                new AvaloniaXamlIlConstructorServiceProviderTransformer(),
+                new AvaloniaXamlIlTransitionsTypeMetadataTransformer()
+            );
+            
+            // After everything else
+            
+            Transformers.Add(new AddNameScopeRegistration());
+            Transformers.Add(new AvaloniaXamlIlMetadataRemover());
+
+        }
+
+        public AvaloniaXamlIlCompiler(XamlIlTransformerConfiguration configuration,
+            IXamlIlTypeBuilder contextTypeBuilder) : this(configuration)
+        {
+            _contextType = CreateContextType(contextTypeBuilder);
+        }
+
+        
+        public AvaloniaXamlIlCompiler(XamlIlTransformerConfiguration configuration,
+            IXamlIlType contextType) : this(configuration)
+        {
+            _contextType = contextType;
+        }
+        
+        public const string PopulateName = "__AvaloniaXamlIlPopulate";
+        public const string BuildName = "__AvaloniaXamlIlBuild";
+
+        public bool IsDesignMode
+        {
+            get => _designTransformer.IsDesignMode;
+            set => _designTransformer.IsDesignMode = value;
+        }
+
+        public void ParseAndCompile(string xaml, string baseUri, IFileSource fileSource, IXamlIlTypeBuilder tb, IXamlIlType overrideRootType)
+        {
+            var parsed = XDocumentXamlIlParser.Parse(xaml, new Dictionary<string, string>
+            {
+                {XamlNamespaces.Blend2008, XamlNamespaces.Blend2008}
+            });
+            
+            var rootObject = (XamlIlAstObjectNode)parsed.Root;
+
+            var classDirective = rootObject.Children
+                .OfType<XamlIlAstXmlDirective>().FirstOrDefault(x =>
+                    x.Namespace == XamlNamespaces.Xaml2006
+                    && x.Name == "Class");
+
+            var rootType =
+                classDirective != null ?
+                    new XamlIlAstClrTypeReference(classDirective,
+                        _configuration.TypeSystem.GetType(((XamlIlAstTextNode)classDirective.Values[0]).Text),
+                        false) :
+                    XamlIlTypeReferenceResolver.ResolveType(CreateTransformationContext(parsed, true),
+                        (XamlIlAstXmlTypeReference)rootObject.Type, true);
+            
+            
+            if (overrideRootType != null)
+            {
+                
+
+                if (!rootType.Type.IsAssignableFrom(overrideRootType))
+                    throw new XamlIlLoadException(
+                        $"Unable to substitute {rootType.Type.GetFqn()} with {overrideRootType.GetFqn()}", rootObject);
+                rootType = new XamlIlAstClrTypeReference(rootObject, overrideRootType, false);
+            }
+
+            rootObject.Type = rootType;
+
+            Transform(parsed);
+            Compile(parsed, tb, _contextType, PopulateName, BuildName, "__AvaloniaXamlIlNsInfo", baseUri, fileSource);
+            
+        }
+        
+        
+    }
+}

+ 176 - 0
src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/AvaloniaXamlIlLanguage.cs

@@ -0,0 +1,176 @@
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+using Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers;
+using XamlIl;
+using XamlIl.Ast;
+using XamlIl.Transform;
+using XamlIl.TypeSystem;
+
+namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
+{
+    /*
+        This file is used in the build task.
+        ONLY use types from netstandard and XamlIl. NO dependencies on Avalonia are allowed. Only strings.
+        No, nameof isn't welcome here either
+     */
+    
+    class AvaloniaXamlIlLanguage
+    {
+        public static XamlIlLanguageTypeMappings Configure(IXamlIlTypeSystem typeSystem)
+        {
+            var runtimeHelpers = typeSystem.GetType("Avalonia.Markup.Xaml.XamlIl.Runtime.XamlIlRuntimeHelpers");
+            var assignBindingAttribute = typeSystem.GetType("Avalonia.Data.AssignBindingAttribute");
+            var bindingType = typeSystem.GetType("Avalonia.Data.IBinding");
+            var rv = new XamlIlLanguageTypeMappings(typeSystem)
+            {
+                SupportInitialize = typeSystem.GetType("System.ComponentModel.ISupportInitialize"),
+                XmlnsAttributes =
+                {
+                    typeSystem.GetType("Avalonia.Metadata.XmlnsDefinitionAttribute"),
+                    typeSystem.FindType("Portable.Xaml.Markup.XmlnsDefinitionAttribute")
+                },
+                ContentAttributes =
+                {
+                    typeSystem.GetType("Avalonia.Metadata.ContentAttribute")
+                },
+                ProvideValueTarget = typeSystem.GetType("Portable.Xaml.Markup.IProvideValueTarget"),
+                RootObjectProvider = typeSystem.GetType("Portable.Xaml.IRootObjectProvider"),
+                UriContextProvider = typeSystem.GetType("Portable.Xaml.Markup.IUriContext"),
+                ParentStackProvider =
+                    typeSystem.GetType("Avalonia.Markup.Xaml.XamlIl.Runtime.IAvaloniaXamlIlParentStackProvider"),
+
+                XmlNamespaceInfoProvider =
+                    typeSystem.GetType("Avalonia.Markup.Xaml.XamlIl.Runtime.IAvaloniaXamlIlXmlNamespaceInfoProvider"),
+                DeferredContentPropertyAttributes = {typeSystem.GetType("Avalonia.Metadata.TemplateContentAttribute")},
+                DeferredContentExecutorCustomization =
+                    runtimeHelpers.FindMethod(m => m.Name == "DeferredTransformationFactoryV1"),
+                UsableDuringInitializationAttributes =
+                {
+                    typeSystem.GetType("Portable.Xaml.Markup.UsableDuringInitializationAttribute"),
+                    typeSystem.GetType("Avalonia.Metadata.UsableDuringInitializationAttribute"),
+                },
+                InnerServiceProviderFactoryMethod =
+                    runtimeHelpers.FindMethod(m => m.Name == "CreateInnerServiceProviderV1"),
+                ProvideValueTargetPropertyEmitter = XamlIlAvaloniaPropertyHelper.Emit,
+            };
+            rv.CustomAttributeResolver = new AttributeResolver(typeSystem, rv);
+            return rv;
+        }
+
+        class AttributeResolver : IXamlIlCustomAttributeResolver
+        {
+            private readonly IXamlIlType _typeConverterAttribute;
+
+            private readonly List<KeyValuePair<IXamlIlType, IXamlIlType>> _converters =
+                new List<KeyValuePair<IXamlIlType, IXamlIlType>>();
+
+            private readonly IXamlIlType _avaloniaList;
+            private readonly IXamlIlType _avaloniaListConverter;
+
+
+            public AttributeResolver(IXamlIlTypeSystem typeSystem, XamlIlLanguageTypeMappings mappings)
+            {
+                _typeConverterAttribute = mappings.TypeConverterAttributes.First();
+
+                void AddType(IXamlIlType type, IXamlIlType conv) 
+                    => _converters.Add(new KeyValuePair<IXamlIlType, IXamlIlType>(type, conv));
+
+                void Add(string type, string conv)
+                    => AddType(typeSystem.GetType(type), typeSystem.GetType(conv));
+                
+                
+                //Add("Avalonia.AvaloniaProperty","Avalonia.Markup.Xaml.Converters.AvaloniaPropertyTypeConverter");
+                Add("Avalonia.Media.Imaging.IBitmap","Avalonia.Markup.Xaml.Converters.BitmapTypeConverter");
+                var ilist = typeSystem.GetType("System.Collections.Generic.IList`1");
+                AddType(ilist.MakeGenericType(typeSystem.GetType("Avalonia.Point")),
+                    typeSystem.GetType("Avalonia.Markup.Xaml.Converters.PointsListTypeConverter"));
+                Add("Avalonia.Controls.Templates.IMemberSelector",
+                    "Avalonia.Markup.Xaml.Converters.MemberSelectorTypeConverter");
+                Add("Avalonia.Styling.Selector","Avalonia.Markup.Xaml.Converters.SelectorTypeConverter");
+                Add("Avalonia.Controls.WindowIcon","Avalonia.Markup.Xaml.Converters.IconTypeConverter");
+                Add("System.Globalization.CultureInfo", "System.ComponentModel.CultureInfoConverter");
+                Add("System.Uri", "Avalonia.Markup.Xaml.Converters.AvaloniaUriTypeConverter");
+                Add("System.TimeSpan", "Avalonia.Markup.Xaml.Converters.TimeSpanTypeConverter");
+                Add("Avalonia.Media.FontFamily","Avalonia.Markup.Xaml.Converters.FontFamilyTypeConverter");
+                _avaloniaList = typeSystem.GetType("Avalonia.Collections.AvaloniaList`1");
+                _avaloniaListConverter = typeSystem.GetType("Avalonia.Collections.AvaloniaListConverter`1");
+            }
+
+            IXamlIlType LookupConverter(IXamlIlType type)
+            {
+                foreach(var p in _converters)
+                    if (p.Key.Equals(type))
+                        return p.Value;
+                if (type.GenericTypeDefinition?.Equals(_avaloniaList) == true)
+                    return _avaloniaListConverter.MakeGenericType(type.GenericArguments[0]);
+                return null;
+            }
+
+            class ConstructedAttribute : IXamlIlCustomAttribute
+            {
+                public bool Equals(IXamlIlCustomAttribute other) => false;
+                
+                public IXamlIlType Type { get; }
+                public List<object> Parameters { get; }
+                public Dictionary<string, object> Properties { get; }
+
+                public ConstructedAttribute(IXamlIlType type, List<object> parameters, Dictionary<string, object> properties)
+                {
+                    Type = type;
+                    Parameters = parameters ?? new List<object>();
+                    Properties = properties ?? new Dictionary<string, object>();
+                }
+            }
+            
+            public IXamlIlCustomAttribute GetCustomAttribute(IXamlIlType type, IXamlIlType attributeType)
+            {
+                if (attributeType.Equals(_typeConverterAttribute))
+                {
+                    var conv = LookupConverter(type);
+                    if (conv != null)
+                        return new ConstructedAttribute(_typeConverterAttribute, new List<object>() {conv}, null);
+                }
+
+                return null;
+            }
+
+            public IXamlIlCustomAttribute GetCustomAttribute(IXamlIlProperty property, IXamlIlType attributeType)
+            {
+                return null;
+            }
+        }
+
+        public static bool CustomValueConverter(XamlIlAstTransformationContext context,
+            IXamlIlAstValueNode node, IXamlIlType type, out IXamlIlAstValueNode result)
+        {
+            if (type.FullName == "System.TimeSpan" 
+                && node is XamlIlAstTextNode tn
+                && !tn.Text.Contains(":"))
+            {
+                var seconds = double.Parse(tn.Text, CultureInfo.InvariantCulture);
+                result = new XamlIlStaticOrTargetedReturnMethodCallNode(tn,
+                    type.FindMethod("FromSeconds", type, false, context.Configuration.WellKnownTypes.Double),
+                    new[]
+                    {
+                        new XamlIlConstantNode(tn, context.Configuration.WellKnownTypes.Double, seconds)
+                    });
+                return true;
+            }
+
+            if (type.FullName == "Avalonia.AvaloniaProperty")
+            {
+                var scope = context.ParentNodes().OfType<AvaloniaXamlIlTargetTypeMetadataNode>().FirstOrDefault();
+                if (scope == null)
+                    throw new XamlIlLoadException("Unable to find the parent scope for AvaloniaProperty lookup", node);
+                if (!(node is XamlIlAstTextNode text))
+                    throw new XamlIlLoadException("Property should be a text node", node);
+                result = XamlIlAvaloniaPropertyHelper.CreateNode(context, text.Text, scope.TargetType, text);
+                return true;
+            }
+
+            result = null;
+            return false;
+        }
+    }
+}

+ 94 - 0
src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AddNameScopeRegistration.cs

@@ -0,0 +1,94 @@
+using System;
+using System.Linq;
+using XamlIl.Ast;
+using XamlIl.Transform;
+using XamlIl.TypeSystem;
+
+namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
+{
+    class AddNameScopeRegistration : IXamlIlAstTransformer
+    {
+        public IXamlIlAstNode Transform(XamlIlAstTransformationContext context, IXamlIlAstNode node)
+        {
+            if (node is XamlIlPropertyAssignmentNode pa
+                && pa.Property.Name == "Name"
+                && pa.Property.DeclaringType.FullName == "Avalonia.StyledElement")
+            {
+                if (context.ParentNodes().FirstOrDefault() is XamlIlManipulationGroupNode mg
+                    && mg.Children.OfType<ScopeRegistrationNode>().Any())
+                    return node;
+                
+                IXamlIlAstValueNode value = null;
+                for (var c = 0; c < pa.Values.Count; c++)
+                    if (pa.Values[c].Type.GetClrType().Equals(context.Configuration.WellKnownTypes.String))
+                    {
+                        value = pa.Values[c];
+                        if (!(value is XamlIlAstTextNode))
+                        {
+                            var local = new XamlIlAstCompilerLocalNode(value);
+                            // Wrap original in local initialization
+                            pa.Values[c] = new XamlIlAstLocalInitializationNodeEmitter(value, value, local);
+                            // Use local
+                            value = local;
+                        }
+
+                        break;
+                    }
+
+                if (value != null)
+                    return new XamlIlManipulationGroupNode(pa)
+                    {
+                        Children =
+                        {
+                            pa,
+                            new ScopeRegistrationNode(value)
+                        }
+                    };
+            }
+
+            return node;
+        }
+
+        class ScopeRegistrationNode : XamlIlAstNode, IXamlIlAstManipulationNode, IXamlIlAstEmitableNode
+        {
+            public IXamlIlAstValueNode Value { get; set; }
+            public ScopeRegistrationNode(IXamlIlAstValueNode value) : base(value)
+            {
+                Value = value;
+            }
+
+            public override void VisitChildren(IXamlIlAstVisitor visitor)
+                => Value = (IXamlIlAstValueNode)Value.Visit(visitor);
+
+            public XamlIlNodeEmitResult Emit(XamlIlEmitContext context, IXamlIlEmitter codeGen)
+            {
+                var exts = context.Configuration.TypeSystem.GetType("Avalonia.Controls.NameScopeExtensions");
+                var findNameScope = exts.FindMethod(m => m.Name == "FindNameScope");
+                var registerMethod = findNameScope.ReturnType.FindMethod(m => m.Name == "Register");
+                using (var targetLoc = context.GetLocal(context.Configuration.WellKnownTypes.Object))
+                using (var nameScopeLoc = context.GetLocal(findNameScope.ReturnType))
+                {
+                    var exit = codeGen.DefineLabel();
+                    codeGen
+                        // var target = {pop}    
+                        .Stloc(targetLoc.Local)
+                        // var scope = target.FindNameScope()
+                        .Ldloc(targetLoc.Local)
+                        .Castclass(findNameScope.Parameters[0])
+                        .EmitCall(findNameScope)
+                        .Stloc(nameScopeLoc.Local)
+                        // if({scope} != null) goto call;
+                        .Ldloc(nameScopeLoc.Local)
+                        .Brfalse(exit)
+                        .Ldloc(nameScopeLoc.Local);
+                    context.Emit(Value, codeGen, Value.Type.GetClrType());
+                    codeGen
+                        .Ldloc(targetLoc.Local)
+                        .EmitCall(registerMethod)
+                        .MarkLabel(exit);
+                }
+                return XamlIlNodeEmitResult.Void(1);
+            }
+        }
+    }
+}

+ 20 - 0
src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaBindingExtensionHackTransformer.cs

@@ -0,0 +1,20 @@
+using XamlIl.Ast;
+using XamlIl.Transform;
+
+namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
+{
+    class AvaloniaBindingExtensionHackTransformer : IXamlIlAstTransformer
+    {
+        public IXamlIlAstNode Transform(XamlIlAstTransformationContext context, IXamlIlAstNode node)
+        {
+            // Our code base expects XAML parser to prefer `FooExtension` to `Foo` even with `<Foo>` syntax
+            // This is the legacy of Portable.Xaml, so we emulate that behavior here
+
+            if (node is XamlIlAstXmlTypeReference tref
+                && tref.Name == "Binding"
+                && tref.XmlNamespace == "https://github.com/avaloniaui")
+                tref.IsMarkupExtension = true;
+            return node;
+        }
+    }
+}

+ 24 - 0
src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlAvaloniaPropertyResolver.cs

@@ -0,0 +1,24 @@
+using System.Linq;
+using XamlIl.Ast;
+using XamlIl.Transform;
+
+namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
+{
+    class AvaloniaXamlIlAvaloniaPropertyResolver : IXamlIlAstTransformer
+    {
+        public IXamlIlAstNode Transform(XamlIlAstTransformationContext context, IXamlIlAstNode node)
+        {
+            if (node is XamlIlAstClrProperty prop)
+            {
+                var n = prop.Name + "Property";
+                var field =
+                    prop.DeclaringType.Fields
+                    .FirstOrDefault(f => f.Name == n);
+                if (field != null)
+                    return new XamlIlAvaloniaProperty(prop, field, context.GetAvaloniaTypes());
+            }
+
+            return node;
+        }
+    }
+}

+ 47 - 0
src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlConstructorServiceProviderTransformer.cs

@@ -0,0 +1,47 @@
+using System.Linq;
+using XamlIl.Ast;
+using XamlIl.Transform;
+using XamlIl.TypeSystem;
+
+namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
+{
+    class AvaloniaXamlIlConstructorServiceProviderTransformer : IXamlIlAstTransformer
+    {
+        public IXamlIlAstNode Transform(XamlIlAstTransformationContext context, IXamlIlAstNode node)
+        {
+            if (node is XamlIlAstObjectNode on && on.Arguments.Count == 0)
+            {
+                var ctors = on.Type.GetClrType().Constructors;
+                if (!ctors.Any(c => c.IsPublic && !c.IsStatic && c.Parameters.Count == 0))
+                {
+                    var sp = context.Configuration.TypeMappings.ServiceProvider;
+                    if (ctors.Any(c =>
+                        c.IsPublic && !c.IsStatic && c.Parameters.Count == 1 && c.Parameters[0]
+                            .Equals(sp)))
+                    {
+                        on.Arguments.Add(new InjectServiceProviderNode(sp, on));
+                    }
+                }
+            }
+
+            return node;
+        }
+
+        class InjectServiceProviderNode : XamlIlAstNode, IXamlIlAstValueNode,IXamlIlAstNodeNeedsParentStack,
+            IXamlIlAstEmitableNode
+        {
+            public InjectServiceProviderNode(IXamlIlType type, IXamlIlLineInfo lineInfo) : base(lineInfo)
+            {
+                Type = new XamlIlAstClrTypeReference(lineInfo, type, false);
+            }
+
+            public IXamlIlAstTypeReference Type { get; }
+            public bool NeedsParentStack => true;
+            public XamlIlNodeEmitResult Emit(XamlIlEmitContext context, IXamlIlEmitter codeGen)
+            {
+                codeGen.Ldloc(context.ContextLocal);
+                return XamlIlNodeEmitResult.Type(0, Type.GetClrType());
+            }
+        }
+    }
+}

+ 71 - 0
src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlControlTemplateTargetTypeMetadataTransformer.cs

@@ -0,0 +1,71 @@
+using System.Linq;
+using XamlIl.Ast;
+using XamlIl.Transform;
+using XamlIl.TypeSystem;
+
+namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
+{
+    class AvaloniaXamlIlControlTemplateTargetTypeMetadataTransformer : IXamlIlAstTransformer
+    {
+        public IXamlIlAstNode Transform(XamlIlAstTransformationContext context, IXamlIlAstNode node)
+        {
+            if (!(node is XamlIlAstObjectNode on
+                  && on.Type.GetClrType().FullName == "Avalonia.Markup.Xaml.Templates.ControlTemplate"))
+                return node;
+            var tt = on.Children.OfType<XamlIlAstXamlPropertyValueNode>().FirstOrDefault(ch =>
+                                              ch.Property.GetClrProperty().Name == "TargetType");
+
+            if (context.ParentNodes().FirstOrDefault() is AvaloniaXamlIlTargetTypeMetadataNode)
+                // Deja vu. I've just been in this place before
+                return node;
+
+            IXamlIlAstTypeReference targetType;
+
+            var templatableBaseType = context.Configuration.TypeSystem.GetType("Avalonia.Controls.Control");
+            
+            if ((tt?.Values.FirstOrDefault() is XamlIlTypeExtensionNode tn))
+            {
+                targetType = tn.Type;
+            }
+            else
+            {
+                var parentScope = context.ParentNodes().OfType<AvaloniaXamlIlTargetTypeMetadataNode>()
+                    .FirstOrDefault();
+                if (parentScope?.ScopeType == AvaloniaXamlIlTargetTypeMetadataNode.ScopeTypes.Style)
+                    targetType = parentScope.TargetType;
+                else if (context.ParentNodes().Skip(1).FirstOrDefault() is XamlIlAstObjectNode directParentNode
+                         && templatableBaseType.IsAssignableFrom(directParentNode.Type.GetClrType()))
+                    targetType = directParentNode.Type;
+                else
+                    targetType = new XamlIlAstClrTypeReference(node,
+                        templatableBaseType, false);
+            }
+                
+                
+
+            return new AvaloniaXamlIlTargetTypeMetadataNode(on, targetType,
+                AvaloniaXamlIlTargetTypeMetadataNode.ScopeTypes.ControlTemplate);
+        }
+    }
+
+    class AvaloniaXamlIlTargetTypeMetadataNode : XamlIlValueWithSideEffectNodeBase
+    {
+        public IXamlIlAstTypeReference TargetType { get; set; }
+        public ScopeTypes ScopeType { get; }
+
+        public enum ScopeTypes
+        {
+            Style,
+            ControlTemplate,
+            Transitions
+        }
+        
+        public AvaloniaXamlIlTargetTypeMetadataNode(IXamlIlAstValueNode value, IXamlIlAstTypeReference targetType,
+            ScopeTypes type)
+            : base(value, value)
+        {
+            TargetType = targetType;
+            ScopeType = type;
+        }
+    }
+}

+ 63 - 0
src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlDesignPropertiesTransformer.cs

@@ -0,0 +1,63 @@
+using System.Collections.Generic;
+using System.Linq;
+using XamlIl;
+using XamlIl.Ast;
+using XamlIl.Transform;
+
+namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
+{
+    class AvaloniaXamlIlDesignPropertiesTransformer : IXamlIlAstTransformer
+    {
+        public bool IsDesignMode { get; set; }
+
+        private static Dictionary<string, string> DesignDirectives = new Dictionary<string, string>()
+        {
+            ["DataContext"] = "DataContext",
+            ["DesignWidth"] = "Width", ["DesignHeight"] = "Height", ["PreviewWith"] = "PreviewWith"
+        };
+
+        private const string AvaloniaNs = "https://github.com/avaloniaui";
+        public IXamlIlAstNode Transform(XamlIlAstTransformationContext context, IXamlIlAstNode node)
+        {
+            if (node is XamlIlAstObjectNode on)
+            {
+                for (var c=0; c<on.Children.Count;)
+                {
+                    var ch = on.Children[c];
+                    if (ch is XamlIlAstXmlDirective directive
+                        && directive.Namespace == XamlNamespaces.Blend2008
+                        && DesignDirectives.TryGetValue(directive.Name, out var mapTo))
+                    {
+                        if (!IsDesignMode)
+                            // Just remove it from AST in non-design mode
+                            on.Children.RemoveAt(c);
+                        else
+                        {
+                            // Map to an actual property in `Design` class
+                            on.Children[c] = new XamlIlAstXamlPropertyValueNode(ch,
+                                new XamlIlAstNamePropertyReference(ch,
+                                    new XamlIlAstXmlTypeReference(ch, AvaloniaNs, "Design"),
+                                    mapTo, on.Type), directive.Values);
+                            c++;
+                        }
+                    }
+                    // Remove all "Design" attached properties in non-design mode
+                    else if (
+                        !IsDesignMode
+                        && ch is XamlIlAstXamlPropertyValueNode pv
+                        && pv.Property is XamlIlAstNamePropertyReference pref
+                        && pref.DeclaringType is XamlIlAstXmlTypeReference dref
+                        && dref.XmlNamespace == AvaloniaNs && dref.Name == "Design"
+                    )
+                    {
+                        on.Children.RemoveAt(c);
+                    }
+                    else
+                        c++;
+                }
+            }
+
+            return node;
+        }
+    }
+}

+ 17 - 0
src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlMetadataRemover.cs

@@ -0,0 +1,17 @@
+using System.Linq;
+using XamlIl.Ast;
+using XamlIl.Transform;
+
+namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
+{
+    class AvaloniaXamlIlMetadataRemover : IXamlIlAstTransformer
+    {
+        public IXamlIlAstNode Transform(XamlIlAstTransformationContext context, IXamlIlAstNode node)
+        {
+            if (node is AvaloniaXamlIlTargetTypeMetadataNode md)
+                return md.Value;
+
+            return node;
+        }
+    }
+}

+ 338 - 0
src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlSelectorTransformer.cs

@@ -0,0 +1,338 @@
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+using Avalonia.Markup.Parsers;
+using XamlIl;
+using XamlIl.Ast;
+using XamlIl.Transform;
+using XamlIl.Transform.Transformers;
+using XamlIl.TypeSystem;
+
+namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
+{
+    class AvaloniaXamlIlSelectorTransformer : IXamlIlAstTransformer
+    {
+        public IXamlIlAstNode Transform(XamlIlAstTransformationContext context, IXamlIlAstNode node)
+        {
+            if (!(node is XamlIlAstObjectNode on && on.Type.GetClrType().FullName == "Avalonia.Styling.Style"))
+                return node;
+
+            var pn = on.Children.OfType<XamlIlAstXamlPropertyValueNode>()
+                .FirstOrDefault(p => p.Property.GetClrProperty().Name == "Selector");
+
+            if (pn == null)
+                return node;
+
+            if (pn.Values.Count != 1)
+                throw new XamlIlParseException("Selector property should should have exactly one value", node);
+            
+            if (pn.Values[0] is XamlIlSelectorNode)
+                //Deja vu. I've just been in this place before
+                return node;
+            
+            if (!(pn.Values[0] is XamlIlAstTextNode tn))
+                throw new XamlIlParseException("Selector property should be a text node", node);
+
+            var selectorType = pn.Property.GetClrProperty().Getter.ReturnType;
+            var initialNode = new XamlIlSelectorInitialNode(node, selectorType);
+            XamlIlSelectorNode Create(IEnumerable<SelectorGrammar.ISyntax> syntax,
+                Func<string, string, XamlIlAstClrTypeReference> typeResolver)
+            {
+                XamlIlSelectorNode result = initialNode;
+                XamlIlOrSelectorNode results = null;
+                foreach (var i in syntax)
+                {
+                    switch (i)
+                    {
+
+                        case SelectorGrammar.OfTypeSyntax ofType:
+                            result = new XamlIlTypeSelector(result, typeResolver(ofType.Xmlns, ofType.TypeName).Type, true);
+                            break;
+                        case SelectorGrammar.IsSyntax @is:
+                            result = new XamlIlTypeSelector(result, typeResolver(@is.Xmlns, @is.TypeName).Type, false);
+                            break;
+                        case SelectorGrammar.ClassSyntax @class:
+                            result = new XamlIlStringSelector(result, XamlIlStringSelector.SelectorType.Class, @class.Class);
+                            break;
+                        case SelectorGrammar.NameSyntax name:
+                            result = new XamlIlStringSelector(result, XamlIlStringSelector.SelectorType.Name, name.Name);
+                            break;
+                        case SelectorGrammar.PropertySyntax property:
+                        {
+                            var type = result?.TargetType;
+
+                            if (type == null)
+                                throw new XamlIlParseException("Property selectors must be applied to a type.", node);
+
+                            var targetProperty =
+                                type.GetAllProperties().FirstOrDefault(p => p.Name == property.Property);
+
+                            if (targetProperty == null)
+                                throw new XamlIlParseException($"Cannot find '{property.Property}' on '{type}", node);
+
+                            if (!XamlIlTransformHelpers.TryGetCorrectlyTypedValue(context,
+                                new XamlIlAstTextNode(node, property.Value, context.Configuration.WellKnownTypes.String),
+                                targetProperty.PropertyType, out var typedValue))
+                                throw new XamlIlParseException(
+                                    $"Cannot convert '{property.Value}' to '{targetProperty.PropertyType.GetFqn()}",
+                                    node);
+
+                            result = new XamlIlPropertyEqualsSelector(result, targetProperty, typedValue);
+                            break;
+                        }
+                        case SelectorGrammar.ChildSyntax child:
+                            result = new XamlIlCombinatorSelector(result, XamlIlCombinatorSelector.SelectorType.Child);
+                            break;
+                        case SelectorGrammar.DescendantSyntax descendant:
+                            result = new XamlIlCombinatorSelector(result, XamlIlCombinatorSelector.SelectorType.Descendant);
+                            break;
+                        case SelectorGrammar.TemplateSyntax template:
+                            result = new XamlIlCombinatorSelector(result, XamlIlCombinatorSelector.SelectorType.Template);
+                            break;
+                        case SelectorGrammar.NotSyntax not:
+                            result = new XamlIlNotSelector(result, Create(not.Argument, typeResolver));
+                            break;
+                        case SelectorGrammar.CommaSyntax comma:
+                            if (results == null) 
+                                results = new XamlIlOrSelectorNode(node, selectorType);
+                            results.Add(result);
+                            result = initialNode;
+                            break;
+                        default:
+                            throw new XamlIlParseException($"Unsupported selector grammar '{i.GetType()}'.", node);
+                    }
+                }
+
+                return results ?? result;
+            }
+
+            IEnumerable<SelectorGrammar.ISyntax> parsed;
+            try
+            {
+                parsed = SelectorGrammar.Parse(tn.Text);
+            }
+            catch (Exception e)
+            {
+                throw new XamlIlParseException("Unable to parse selector: " + e.Message, node);
+            }
+
+            var selector = Create(parsed, (p, n) 
+                => XamlIlTypeReferenceResolver.ResolveType(context, $"{p}:{n}", true, node, true));
+            pn.Values[0] = selector;
+
+            return new AvaloniaXamlIlTargetTypeMetadataNode(on,
+                new XamlIlAstClrTypeReference(selector, selector.TargetType, false),
+                AvaloniaXamlIlTargetTypeMetadataNode.ScopeTypes.Style);
+        }
+
+    }
+
+
+    
+    abstract class XamlIlSelectorNode : XamlIlAstNode, IXamlIlAstValueNode, IXamlIlAstEmitableNode
+    {
+        protected XamlIlSelectorNode Previous { get; }
+        public abstract IXamlIlType TargetType { get; }
+
+        public XamlIlSelectorNode(XamlIlSelectorNode previous,
+            IXamlIlLineInfo info = null,
+            IXamlIlType selectorType = null) : base(info ?? previous)
+        {
+            Previous = previous;
+            Type = selectorType == null ? previous.Type : new XamlIlAstClrTypeReference(this, selectorType, false);
+        }
+
+        public IXamlIlAstTypeReference Type { get; }
+
+        public virtual XamlIlNodeEmitResult Emit(XamlIlEmitContext context, IXamlIlEmitter codeGen)
+        {
+            if (Previous != null)
+                context.Emit(Previous, codeGen, Type.GetClrType());
+            DoEmit(context, codeGen);
+            return XamlIlNodeEmitResult.Type(0, Type.GetClrType());
+        }
+        
+        protected abstract void DoEmit(XamlIlEmitContext context, IXamlIlEmitter codeGen);
+
+        protected void EmitCall(XamlIlEmitContext context, IXamlIlEmitter codeGen, Func<IXamlIlMethod, bool> method)
+        {
+            var selectors = context.Configuration.TypeSystem.GetType("Avalonia.Styling.Selectors");
+            var found = selectors.FindMethod(m => m.IsStatic && m.Parameters.Count > 0 &&
+                                      m.Parameters[0].FullName == "Avalonia.Styling.Selector"
+                                      && method(m));
+            codeGen.EmitCall(found);
+        }
+    }
+    
+    class XamlIlSelectorInitialNode : XamlIlSelectorNode
+    {
+        public XamlIlSelectorInitialNode(IXamlIlLineInfo info,
+            IXamlIlType selectorType) : base(null, info, selectorType)
+        {
+        }
+
+        public override IXamlIlType TargetType => null;
+        protected override void DoEmit(XamlIlEmitContext context, IXamlIlEmitter codeGen) => codeGen.Ldnull();
+    }
+
+    class XamlIlTypeSelector : XamlIlSelectorNode
+    {
+        public bool Concrete { get; }
+
+        public XamlIlTypeSelector(XamlIlSelectorNode previous, IXamlIlType type, bool concrete) : base(previous)
+        {
+            TargetType = type;
+            Concrete = concrete;
+        }
+
+        public override IXamlIlType TargetType { get; }
+        protected override void DoEmit(XamlIlEmitContext context, IXamlIlEmitter codeGen)
+        {
+            var name = Concrete ? "OfType" : "Is";
+            codeGen.Ldtype(TargetType);
+            EmitCall(context, codeGen,
+                m => m.Name == name && m.Parameters.Count == 2 && m.Parameters[1].FullName == "System.Type");
+        }
+    }
+    
+    class XamlIlStringSelector : XamlIlSelectorNode
+    {
+        public string String { get; set; }
+        public enum SelectorType
+        {
+            Class,
+            Name
+        }
+
+        private SelectorType _type;
+
+        public XamlIlStringSelector(XamlIlSelectorNode previous, SelectorType type, string s) : base(previous)
+        {
+            _type = type;
+            String = s;
+        }
+
+
+        public override IXamlIlType TargetType => Previous?.TargetType;
+        protected override void DoEmit(XamlIlEmitContext context, IXamlIlEmitter codeGen)
+        {
+            codeGen.Ldstr(String);
+            var name = _type.ToString();
+            EmitCall(context, codeGen,
+                m => m.Name == name && m.Parameters.Count == 2 && m.Parameters[1].FullName == "System.String");
+        }
+    }
+
+    class XamlIlCombinatorSelector : XamlIlSelectorNode
+    {
+        private readonly SelectorType _type;
+
+        public enum SelectorType
+        {
+            Child,
+            Descendant,
+            Template
+        }
+        public XamlIlCombinatorSelector(XamlIlSelectorNode previous, SelectorType type) : base(previous)
+        {
+            _type = type;
+        }
+
+        public override IXamlIlType TargetType => null;
+        protected override void DoEmit(XamlIlEmitContext context, IXamlIlEmitter codeGen)
+        {
+            var name = _type.ToString();
+            EmitCall(context, codeGen,
+                m => m.Name == name && m.Parameters.Count == 1);
+        }
+    }
+
+    class XamlIlNotSelector : XamlIlSelectorNode
+    {
+        public XamlIlSelectorNode Argument { get; }
+
+        public XamlIlNotSelector(XamlIlSelectorNode previous, XamlIlSelectorNode argument) : base(previous)
+        {
+            Argument = argument;
+        }
+
+        public override IXamlIlType TargetType => Previous?.TargetType;
+        protected override void DoEmit(XamlIlEmitContext context, IXamlIlEmitter codeGen)
+        {
+            context.Emit(Argument, codeGen, Type.GetClrType());
+            EmitCall(context, codeGen,
+                m => m.Name == "Not" && m.Parameters.Count == 2 && m.Parameters[1].Equals(Type.GetClrType()));
+        }
+    }
+
+    class XamlIlPropertyEqualsSelector : XamlIlSelectorNode
+    {
+        public XamlIlPropertyEqualsSelector(XamlIlSelectorNode previous,
+            IXamlIlProperty property,
+            IXamlIlAstValueNode value)
+            : base(previous)
+        {
+            Property = property;
+            Value = value;
+        }
+
+        public IXamlIlProperty Property { get; set; }
+        public IXamlIlAstValueNode Value { get; set; }
+        
+        public override IXamlIlType TargetType => Previous?.TargetType;
+        protected override void DoEmit(XamlIlEmitContext context, IXamlIlEmitter codeGen)
+        {
+            if (!XamlIlAvaloniaPropertyHelper.Emit(context, codeGen, Property))
+                throw new XamlIlLoadException(
+                    $"{Property.Name} of {(Property.Setter ?? Property.Getter).DeclaringType.GetFqn()} doesn't seem to be an AvaloniaProperty",
+                    this);
+            context.Emit(Value, codeGen, context.Configuration.WellKnownTypes.Object);
+            EmitCall(context, codeGen,
+                m => m.Name == "PropertyEquals"
+                     && m.Parameters.Count == 3
+                     && m.Parameters[1].FullName == "Avalonia.AvaloniaProperty"
+                     && m.Parameters[2].Equals(context.Configuration.WellKnownTypes.Object));
+        }
+    }
+
+    class XamlIlOrSelectorNode : XamlIlSelectorNode
+    {
+        List<XamlIlSelectorNode> _selectors = new List<XamlIlSelectorNode>();
+        public XamlIlOrSelectorNode(IXamlIlLineInfo info, IXamlIlType selectorType) : base(null, info, selectorType)
+        {
+        }
+
+        public void Add(XamlIlSelectorNode node)
+        {
+            _selectors.Add(node);
+        }
+        
+        //TODO: actually find the type
+        public override IXamlIlType TargetType => _selectors.FirstOrDefault()?.TargetType;
+        protected override void DoEmit(XamlIlEmitContext context, IXamlIlEmitter codeGen)
+        {
+            if (_selectors.Count == 0)
+                throw new XamlIlLoadException("Invalid selector count", this);
+            if (_selectors.Count == 1)
+            {
+                _selectors[0].Emit(context, codeGen);
+                return;
+            }
+            var listType = context.Configuration.TypeSystem.FindType("System.Collections.Generic.List`1")
+                .MakeGenericType(base.Type.GetClrType());
+            var add = listType.FindMethod("Add", context.Configuration.WellKnownTypes.Void, false, Type.GetClrType());
+            codeGen
+                .Newobj(listType.FindConstructor());
+            foreach (var s in _selectors)
+            {
+                codeGen.Dup();
+                context.Emit(s, codeGen, Type.GetClrType());
+                codeGen.EmitCall(add, true);
+            }
+
+            EmitCall(context, codeGen,
+                m => m.Name == "Or" && m.Parameters.Count == 1 && m.Parameters[0].Name.StartsWith("IReadOnlyList"));
+        }
+    }
+}

+ 108 - 0
src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlSetterTransformer.cs

@@ -0,0 +1,108 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using XamlIl;
+using XamlIl.Ast;
+using XamlIl.Transform;
+using XamlIl.Transform.Transformers;
+using XamlIl.TypeSystem;
+
+namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
+{
+    class AvaloniaXamlIlSetterTransformer : IXamlIlAstTransformer
+    {
+        public IXamlIlAstNode Transform(XamlIlAstTransformationContext context, IXamlIlAstNode node)
+        {
+            if (!(node is XamlIlAstObjectNode on
+                  && on.Type.GetClrType().FullName == "Avalonia.Styling.Setter"))
+                return node;
+            var parent = context.ParentNodes().OfType<XamlIlAstObjectNode>()
+                .FirstOrDefault(x => x.Type.GetClrType().FullName == "Avalonia.Styling.Style");
+            if (parent == null)
+                throw new XamlIlParseException(
+                    "Avalonia.Styling.Setter is only valid inside Avalonia.Styling.Style", node);
+            var selectorProperty = parent.Children.OfType<XamlIlAstXamlPropertyValueNode>()
+                .FirstOrDefault(p => p.Property.GetClrProperty().Name == "Selector");
+            if (selectorProperty == null)
+                throw new XamlIlParseException(
+                    "Can not find parent Style Selector", node);
+            var selector = selectorProperty.Values.FirstOrDefault() as XamlIlSelectorNode;
+            if (selector?.TargetType == null)
+                throw new XamlIlParseException(
+                    "Can not resolve parent Style Selector type", node);
+
+
+            var property = @on.Children.OfType<XamlIlAstXamlPropertyValueNode>()
+                .FirstOrDefault(x => x.Property.GetClrProperty().Name == "Property");
+            if (property == null)
+                throw new XamlIlParseException("Setter without a property is not valid", node);
+
+            var propertyName = property.Values.OfType<XamlIlAstTextNode>().FirstOrDefault()?.Text;
+            if (propertyName == null)
+                throw new XamlIlParseException("Setter.Property must be a string", node);
+
+
+            var avaloniaPropertyNode = XamlIlAvaloniaPropertyHelper.CreateNode(context, propertyName,
+                new XamlIlAstClrTypeReference(selector, selector.TargetType, false), property.Values[0]);
+            property.Values = new List<IXamlIlAstValueNode>
+            {
+                avaloniaPropertyNode
+            };
+
+            var valueProperty = on.Children
+                .OfType<XamlIlAstXamlPropertyValueNode>().FirstOrDefault(p => p.Property.GetClrProperty().Name == "Value");
+            if (valueProperty?.Values?.Count == 1 && valueProperty.Values[0] is XamlIlAstTextNode)
+            {
+                var propType = avaloniaPropertyNode.Property.Getter?.ReturnType
+                               ?? avaloniaPropertyNode.Property.Setters.First().Parameters[0];
+                if (!XamlIlTransformHelpers.TryGetCorrectlyTypedValue(context, valueProperty.Values[0],
+                        propType, out var converted))
+                    throw new XamlIlParseException(
+                        $"Unable to convert property value to {propType.GetFqn()}",
+                        valueProperty.Values[0]);
+
+                valueProperty.Property = new SetterValueProperty(valueProperty.Property,
+                    on.Type.GetClrType(), propType, context.GetAvaloniaTypes());
+            }
+
+            return node;
+        }
+
+        class SetterValueProperty : XamlIlAstClrProperty
+        {
+            public SetterValueProperty(IXamlIlLineInfo line, IXamlIlType setterType, IXamlIlType targetType,
+                AvaloniaXamlIlWellKnownTypes types)
+                : base(line, "Value", setterType, null)
+            {
+                Getter = setterType.Methods.First(m => m.Name == "get_Value");
+                var method = setterType.Methods.First(m => m.Name == "set_Value");
+                Setters.Add(new XamlIlDirectCallPropertySetter(method, types.IBinding));
+                Setters.Add(new XamlIlDirectCallPropertySetter(method, types.UnsetValueType));
+                Setters.Add(new XamlIlDirectCallPropertySetter(method, targetType));
+            }
+            
+            class XamlIlDirectCallPropertySetter : IXamlIlPropertySetter
+            {
+                private readonly IXamlIlMethod _method;
+                private readonly IXamlIlType _type;
+                public IXamlIlType TargetType { get; }
+                public PropertySetterBinderParameters BinderParameters { get; } = new PropertySetterBinderParameters();
+                public IReadOnlyList<IXamlIlType> Parameters { get; }
+                public void Emit(IXamlIlEmitter codegen)
+                {
+                    if (_type.IsValueType)
+                        codegen.Box(_type);
+                    codegen.EmitCall(_method, true);
+                }
+
+                public XamlIlDirectCallPropertySetter(IXamlIlMethod method, IXamlIlType type)
+                {
+                    _method = method;
+                    _type = type;
+                    Parameters = new[] {type};
+                    TargetType = method.ThisOrFirstParameter();
+                }
+            }
+        }
+    }
+}

+ 193 - 0
src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlTransformInstanceAttachedProperties.cs

@@ -0,0 +1,193 @@
+using System.Collections.Generic;
+using System.Linq;
+using XamlIl;
+using XamlIl.Ast;
+using XamlIl.Transform;
+using XamlIl.TypeSystem;
+
+namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
+{
+    class AvaloniaXamlIlTransformInstanceAttachedProperties : IXamlIlAstTransformer
+    {
+
+        public IXamlIlAstNode Transform(XamlIlAstTransformationContext context, IXamlIlAstNode node)
+        {
+            if (node is XamlIlAstNamePropertyReference prop 
+                && prop.TargetType is XamlIlAstClrTypeReference targetRef 
+                && prop.DeclaringType is XamlIlAstClrTypeReference declaringRef)
+            {
+                // Target and declared type aren't assignable but both inherit from AvaloniaObject
+                var avaloniaObject = context.Configuration.TypeSystem.FindType("Avalonia.AvaloniaObject");
+                if (avaloniaObject.IsAssignableFrom(targetRef.Type)
+                    && avaloniaObject.IsAssignableFrom(declaringRef.Type)
+                    && !targetRef.Type.IsAssignableFrom(declaringRef.Type))
+                {
+                    // Instance property
+                    var clrProp = declaringRef.Type.GetAllProperties().FirstOrDefault(p => p.Name == prop.Name);
+                    if (clrProp != null
+                        && (clrProp.Getter?.IsStatic == false || clrProp.Setter?.IsStatic == false))
+                    {
+                        var declaringType = (clrProp.Getter ?? clrProp.Setter)?.DeclaringType;
+                        var avaloniaPropertyFieldName = prop.Name + "Property";
+                        var avaloniaPropertyField = declaringType.Fields.FirstOrDefault(f => f.IsStatic && f.Name == avaloniaPropertyFieldName);
+                        if (avaloniaPropertyField != null)
+                        {
+                            var avaloniaPropertyType = avaloniaPropertyField.FieldType;
+                            while (avaloniaPropertyType != null
+                                   && !(avaloniaPropertyType.Namespace == "Avalonia"
+                                        && (avaloniaPropertyType.Name == "AvaloniaProperty"
+                                            || avaloniaPropertyType.Name == "AvaloniaProperty`1"
+                                        )))
+                            {
+                                // Attached properties are handled by vanilla XamlIl
+                                if (avaloniaPropertyType.Name.StartsWith("AttachedProperty"))
+                                    return node;
+                                
+                                avaloniaPropertyType = avaloniaPropertyType.BaseType;
+                            }
+
+                            if (avaloniaPropertyType == null)
+                                return node;
+
+                            if (avaloniaPropertyType.GenericArguments?.Count > 1)
+                                return node;
+
+                            var propertyType = avaloniaPropertyType.GenericArguments?.Count == 1 ?
+                                avaloniaPropertyType.GenericArguments[0] :
+                                context.Configuration.WellKnownTypes.Object;
+
+                            return new AvaloniaAttachedInstanceProperty(prop, context.Configuration,
+                                    declaringType, propertyType, avaloniaPropertyType, avaloniaObject,
+                                    avaloniaPropertyField);
+                        }
+
+                    }
+
+
+                }
+            }
+
+            return node;
+        }
+
+        class AvaloniaAttachedInstanceProperty : XamlIlAstClrProperty, IXamlIlAvaloniaProperty
+        {
+            private readonly XamlIlTransformerConfiguration _config;
+            private readonly IXamlIlType _declaringType;
+            private readonly IXamlIlType _avaloniaPropertyType;
+            private readonly IXamlIlType _avaloniaObject;
+            private readonly IXamlIlField _field;
+
+            public AvaloniaAttachedInstanceProperty(XamlIlAstNamePropertyReference prop,
+                XamlIlTransformerConfiguration config,
+                IXamlIlType declaringType,
+                IXamlIlType type,
+                IXamlIlType avaloniaPropertyType,
+                IXamlIlType avaloniaObject,
+                IXamlIlField field) : base(prop, prop.Name,
+                declaringType, null)
+            
+            
+            {
+                _config = config;
+                _declaringType = declaringType;
+                _avaloniaPropertyType = avaloniaPropertyType;
+                
+                // XamlIl doesn't support generic methods yet
+                if (_avaloniaPropertyType.GenericArguments?.Count > 0)
+                    _avaloniaPropertyType = _avaloniaPropertyType.BaseType;
+                
+                _avaloniaObject = avaloniaObject;
+                _field = field;
+                PropertyType = type;
+                Setters.Add(new SetterMethod(this));
+                Getter = new GetterMethod(this);
+            }
+
+            public IXamlIlType PropertyType { get;  }
+
+            public IXamlIlField AvaloniaProperty => _field;
+            
+            class SetterMethod : IXamlIlPropertySetter
+            {
+                private readonly AvaloniaAttachedInstanceProperty _parent;
+
+                public SetterMethod(AvaloniaAttachedInstanceProperty parent)
+                {
+                    _parent = parent;
+                    Parameters = new[] {_parent._avaloniaObject, _parent.PropertyType};
+                }
+
+                public IXamlIlType TargetType => _parent.DeclaringType;
+                public PropertySetterBinderParameters BinderParameters { get; } = new PropertySetterBinderParameters();
+                public IReadOnlyList<IXamlIlType> Parameters { get; }
+                public void Emit(IXamlIlEmitter emitter)
+                {
+                    var so = _parent._config.WellKnownTypes.Object;
+                    var method = _parent._avaloniaObject
+                        .FindMethod(m => m.IsPublic && !m.IsStatic && m.Name == "SetValue"
+                                         &&
+                                         m.Parameters.Count == 3
+                                         && m.Parameters[0].Equals(_parent._avaloniaPropertyType)
+                                         && m.Parameters[1].Equals(so)
+                                         && m.Parameters[2].IsEnum
+                        );
+                    if (method == null)
+                        throw new XamlIlTypeSystemException(
+                            "Unable to find SetValue(AvaloniaProperty, object, BindingPriority) on AvaloniaObject");
+                    using (var loc = emitter.LocalsPool.GetLocal(_parent.PropertyType))
+                        emitter
+                            .Stloc(loc.Local)
+                            .Ldsfld(_parent._field)
+                            .Ldloc(loc.Local);
+
+                    if(_parent.PropertyType.IsValueType)
+                        emitter.Box(_parent.PropertyType);
+                    emitter        
+                        .Ldc_I4(0)
+                        .EmitCall(method);
+
+                }
+            }
+
+            class GetterMethod :  IXamlIlCustomEmitMethod
+            {
+                public GetterMethod(AvaloniaAttachedInstanceProperty parent) 
+                {
+                    Parent = parent;
+                    DeclaringType = parent._declaringType;
+                    Name = "AvaloniaObject:GetValue_" + Parent.Name;
+                    Parameters = new[] {parent._avaloniaObject};
+                }
+                public AvaloniaAttachedInstanceProperty Parent { get; }
+                public bool IsPublic => true;
+                public bool IsStatic => true;
+                public string Name { get; protected set; }
+                public IXamlIlType DeclaringType { get; }
+
+
+                public bool Equals(IXamlIlMethod other) =>
+                    other is GetterMethod m && m.Name == Name && m.DeclaringType.Equals(DeclaringType);
+                public IXamlIlType ReturnType => Parent.PropertyType;
+                public IReadOnlyList<IXamlIlType> Parameters { get; }
+                public void EmitCall(IXamlIlEmitter emitter)
+                {
+                    var method = Parent._avaloniaObject
+                        .FindMethod(m => m.IsPublic && !m.IsStatic && m.Name == "GetValue"
+                                         &&
+                                         m.Parameters.Count == 1
+                                         && m.Parameters[0].Equals(Parent._avaloniaPropertyType));
+                    if (method == null)
+                        throw new XamlIlTypeSystemException(
+                            "Unable to find T GetValue<T>(AvaloniaProperty<T>) on AvaloniaObject");
+                    emitter
+                        .Ldsfld(Parent._field)
+                        .EmitCall(method);
+                    if (Parent.PropertyType.IsValueType)
+                        emitter.Unbox_Any(Parent.PropertyType);
+
+                }
+            }
+        }
+    }
+}

+ 28 - 0
src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlTransitionsTypeMetadataTransformer.cs

@@ -0,0 +1,28 @@
+using XamlIl.Ast;
+using XamlIl.Transform;
+
+namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
+{
+    class AvaloniaXamlIlTransitionsTypeMetadataTransformer : IXamlIlAstTransformer
+    {
+        public IXamlIlAstNode Transform(XamlIlAstTransformationContext context, IXamlIlAstNode node)
+        {
+            if (node is XamlIlAstObjectNode on)
+            {
+                foreach (var ch in on.Children)
+                {
+                    if (ch is XamlIlAstXamlPropertyValueNode pn
+                        && pn.Property.GetClrProperty().Getter?.ReturnType.Equals(context.GetAvaloniaTypes().Transitions) == true)
+                    {
+                        for (var c = 0; c < pn.Values.Count; c++)
+                        {
+                            pn.Values[c] = new AvaloniaXamlIlTargetTypeMetadataNode(pn.Values[c], on.Type,
+                                AvaloniaXamlIlTargetTypeMetadataNode.ScopeTypes.Transitions);
+                        }
+                    }
+                }
+            }
+            return node;
+        }
+    }
+}

+ 53 - 0
src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlWellKnownTypes.cs

@@ -0,0 +1,53 @@
+using XamlIl.Transform;
+using XamlIl.TypeSystem;
+
+namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
+{
+    class AvaloniaXamlIlWellKnownTypes
+    {
+        public IXamlIlType AvaloniaObject { get; }
+        public IXamlIlType IAvaloniaObject { get; }
+        public IXamlIlType BindingPriority { get; }
+        public IXamlIlType AvaloniaObjectExtensions { get; }
+        public IXamlIlType AvaloniaProperty { get; }
+        public IXamlIlType IBinding { get; }
+        public IXamlIlMethod AvaloniaObjectBindMethod { get; }
+        public IXamlIlMethod AvaloniaObjectSetValueMethod { get; }
+        public IXamlIlType IDisposable { get; }
+        public XamlIlTypeWellKnownTypes XamlIlTypes { get; }
+        public IXamlIlType Transitions { get; }
+        public IXamlIlType AssignBindingAttribute { get; }
+        public IXamlIlType UnsetValueType { get; }
+        
+        public AvaloniaXamlIlWellKnownTypes(XamlIlAstTransformationContext ctx)
+        {
+            XamlIlTypes = ctx.Configuration.WellKnownTypes;
+            AvaloniaObject = ctx.Configuration.TypeSystem.GetType("Avalonia.AvaloniaObject");
+            IAvaloniaObject = ctx.Configuration.TypeSystem.GetType("Avalonia.IAvaloniaObject");
+            AvaloniaObjectExtensions = ctx.Configuration.TypeSystem.GetType("Avalonia.AvaloniaObjectExtensions");
+            AvaloniaProperty = ctx.Configuration.TypeSystem.GetType("Avalonia.AvaloniaProperty");
+            BindingPriority = ctx.Configuration.TypeSystem.GetType("Avalonia.Data.BindingPriority");
+            IBinding = ctx.Configuration.TypeSystem.GetType("Avalonia.Data.IBinding");
+            IDisposable = ctx.Configuration.TypeSystem.GetType("System.IDisposable");
+            Transitions = ctx.Configuration.TypeSystem.GetType("Avalonia.Animation.Transitions");
+            AssignBindingAttribute = ctx.Configuration.TypeSystem.GetType("Avalonia.Data.AssignBindingAttribute");
+            AvaloniaObjectBindMethod = AvaloniaObjectExtensions.FindMethod("Bind", IDisposable, false, IAvaloniaObject,
+                AvaloniaProperty,
+                IBinding, ctx.Configuration.WellKnownTypes.Object);
+            UnsetValueType = ctx.Configuration.TypeSystem.GetType("Avalonia.UnsetValueType");
+            AvaloniaObjectSetValueMethod = AvaloniaObject.FindMethod("SetValue", XamlIlTypes.Void,
+                false, AvaloniaProperty, XamlIlTypes.Object, BindingPriority);
+        }
+    }
+
+    static class AvaloniaXamlIlWellKnownTypesExtensions
+    {
+        public static AvaloniaXamlIlWellKnownTypes GetAvaloniaTypes(this XamlIlAstTransformationContext ctx)
+        {
+            if (ctx.TryGetItem<AvaloniaXamlIlWellKnownTypes>(out var rv))
+                return rv;
+            ctx.SetItem(rv = new AvaloniaXamlIlWellKnownTypes(ctx));
+            return rv;
+        }
+    }
+}

+ 27 - 0
src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/IgnoredDirectivesTransformer.cs

@@ -0,0 +1,27 @@
+using System.Linq;
+using XamlIl;
+using XamlIl.Ast;
+using XamlIl.Transform;
+
+namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
+{
+    class IgnoredDirectivesTransformer : IXamlIlAstTransformer
+    {
+        public IXamlIlAstNode Transform(XamlIlAstTransformationContext context, IXamlIlAstNode node)
+        {
+            if (node is XamlIlAstObjectNode no)
+            {
+                foreach (var d in no.Children.OfType<XamlIlAstXmlDirective>().ToList())
+                {
+                    if (d.Namespace == XamlNamespaces.Xaml2006)
+                    {
+                        if (d.Name == "Precompile" || d.Name == "Class")
+                            no.Children.Remove(d);
+                    }
+                }
+            }
+
+            return node;
+        }
+    }
+}

+ 36 - 0
src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/XNameTransformer.cs

@@ -0,0 +1,36 @@
+using XamlIl;
+using XamlIl.Ast;
+using XamlIl.Transform;
+
+namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
+{
+    class XNameTransformer : IXamlIlAstTransformer
+    {
+        
+        /// <summary>
+        /// Converts x:Name directives to regular Name assignments
+        /// </summary>
+        /// <returns></returns>
+        public IXamlIlAstNode Transform(XamlIlAstTransformationContext context, IXamlIlAstNode node)
+        {
+            if (node is XamlIlAstObjectNode on)
+            {
+                for (var c =0; c< on.Children.Count;c++)
+                {
+                    var ch = on.Children[c];
+                    if (ch is XamlIlAstXmlDirective d
+                        && d.Namespace == XamlNamespaces.Xaml2006
+                        && d.Name == "Name")
+
+
+                        on.Children[c] = new XamlIlAstXamlPropertyValueNode(d,
+                            new XamlIlAstNamePropertyReference(d, on.Type, "Name", on.Type),
+                            d.Values);
+                }
+            }
+
+            return node;
+            
+        }
+    }
+}

+ 186 - 0
src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/XamlIlAvaloniaPropertyHelper.cs

@@ -0,0 +1,186 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Xml;
+using Avalonia.Markup.Xaml.Parsers;
+using Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers;
+using Avalonia.Utilities;
+using XamlIl;
+using XamlIl.Ast;
+using XamlIl.Transform;
+using XamlIl.Transform.Transformers;
+using XamlIl.TypeSystem;
+
+namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
+{
+    class XamlIlAvaloniaPropertyHelper
+    {
+        public static bool Emit(XamlIlEmitContext context, IXamlIlEmitter emitter, XamlIlAstClrProperty property)
+        {
+            if (property is IXamlIlAvaloniaProperty ap)
+            {
+                emitter.Ldsfld(ap.AvaloniaProperty);
+                return true;
+            }
+            var type = property.DeclaringType;
+            var name = property.Name + "Property";
+            var found = type.Fields.FirstOrDefault(f => f.IsStatic && f.Name == name);
+            if (found == null)
+                return false;
+
+            emitter.Ldsfld(found);
+            return true;
+        }
+        
+        public static bool Emit(XamlIlEmitContext context, IXamlIlEmitter emitter, IXamlIlProperty property)
+        {
+            var type = (property.Getter ?? property.Setter).DeclaringType;
+            var name = property.Name + "Property";
+            var found = type.Fields.FirstOrDefault(f => f.IsStatic && f.Name == name);
+            if (found == null)
+                return false;
+
+            emitter.Ldsfld(found);
+            return true;
+        }
+
+        public static XamlIlAvaloniaPropertyNode CreateNode(XamlIlAstTransformationContext context,
+            string propertyName, IXamlIlAstTypeReference selectorTypeReference, IXamlIlLineInfo lineInfo)
+        {
+            XamlIlAstNamePropertyReference forgedReference;
+            
+            var parser = new PropertyParser();
+            
+            var parsedPropertyName = parser.Parse(new CharacterReader(propertyName.AsSpan()));
+            if(parsedPropertyName.owner == null)
+                forgedReference = new XamlIlAstNamePropertyReference(lineInfo, selectorTypeReference,
+                    propertyName, selectorTypeReference);
+            else
+            {
+                var xmlOwner = parsedPropertyName.ns;
+                if (xmlOwner != null)
+                    xmlOwner += ":";
+                xmlOwner += parsedPropertyName.owner;
+                
+                var tref = XamlIlTypeReferenceResolver.ResolveType(context, xmlOwner, false, lineInfo, true);
+                forgedReference = new XamlIlAstNamePropertyReference(lineInfo,
+                    tref, parsedPropertyName.name, tref);
+            }
+
+            var clrProperty =
+                ((XamlIlAstClrProperty)new XamlIlPropertyReferenceResolver().Transform(context,
+                    forgedReference));
+            return new XamlIlAvaloniaPropertyNode(lineInfo,
+                context.Configuration.TypeSystem.GetType("Avalonia.AvaloniaProperty"),
+                clrProperty);
+        }
+    }
+    
+    class XamlIlAvaloniaPropertyNode : XamlIlAstNode, IXamlIlAstValueNode, IXamlIlAstEmitableNode
+    {
+        public XamlIlAvaloniaPropertyNode(IXamlIlLineInfo lineInfo, IXamlIlType type, XamlIlAstClrProperty property) : base(lineInfo)
+        {
+            Type = new XamlIlAstClrTypeReference(this, type, false);
+            Property = property;
+        }
+
+        public XamlIlAstClrProperty Property { get; }
+
+        public IXamlIlAstTypeReference Type { get; }
+        public XamlIlNodeEmitResult Emit(XamlIlEmitContext context, IXamlIlEmitter codeGen)
+        {
+            if (!XamlIlAvaloniaPropertyHelper.Emit(context, codeGen, Property))
+                throw new XamlIlLoadException(Property.Name + " is not an AvaloniaProperty", this);
+            return XamlIlNodeEmitResult.Type(0, Type.GetClrType());
+        }
+    }
+
+    interface IXamlIlAvaloniaProperty
+    {
+        IXamlIlField AvaloniaProperty { get; }
+    }
+    
+    class XamlIlAvaloniaProperty : XamlIlAstClrProperty, IXamlIlAvaloniaProperty
+    {
+        public IXamlIlField AvaloniaProperty { get; }
+        public XamlIlAvaloniaProperty(XamlIlAstClrProperty original, IXamlIlField field,
+            AvaloniaXamlIlWellKnownTypes types)
+            :base(original, original.Name, original.DeclaringType, original.Getter, original.Setters)
+        {
+            AvaloniaProperty = field;
+            CustomAttributes = original.CustomAttributes;
+            if (!original.CustomAttributes.Any(ca => ca.Type.Equals(types.AssignBindingAttribute)))
+                Setters.Insert(0, new BindingSetter(types, original.DeclaringType, field));
+            
+            Setters.Insert(0, new UnsetValueSetter(types, original.DeclaringType, field));
+        }
+
+        abstract class AvaloniaPropertyCustomSetter : IXamlIlPropertySetter
+        {
+            protected AvaloniaXamlIlWellKnownTypes Types;
+            protected IXamlIlField AvaloniaProperty;
+
+            public AvaloniaPropertyCustomSetter(AvaloniaXamlIlWellKnownTypes types,
+                IXamlIlType declaringType,
+                IXamlIlField avaloniaProperty)
+            {
+                Types = types;
+                AvaloniaProperty = avaloniaProperty;
+                TargetType = declaringType;
+            }
+
+            public IXamlIlType TargetType { get; }
+
+            public PropertySetterBinderParameters BinderParameters { get; } = new PropertySetterBinderParameters
+            {
+                AllowXNull = false
+            };
+
+            public IReadOnlyList<IXamlIlType> Parameters { get; set; }
+            public abstract void Emit(IXamlIlEmitter codegen);
+        }
+
+        class BindingSetter : AvaloniaPropertyCustomSetter
+        {
+            public BindingSetter(AvaloniaXamlIlWellKnownTypes types,
+                IXamlIlType declaringType,
+                IXamlIlField avaloniaProperty) : base(types, declaringType, avaloniaProperty)
+            {
+                Parameters = new[] {types.IBinding};
+            }
+
+            public override void Emit(IXamlIlEmitter emitter)
+            {
+                using (var bloc = emitter.LocalsPool.GetLocal(Types.IBinding))
+                    emitter
+                        .Stloc(bloc.Local)
+                        .Ldsfld(AvaloniaProperty)
+                        .Ldloc(bloc.Local)
+                        // TODO: provide anchor?
+                        .Ldnull();
+                emitter.EmitCall(Types.AvaloniaObjectBindMethod, true);
+            }
+        }
+
+        class UnsetValueSetter : AvaloniaPropertyCustomSetter
+        {
+            public UnsetValueSetter(AvaloniaXamlIlWellKnownTypes types, IXamlIlType declaringType, IXamlIlField avaloniaProperty) 
+                : base(types, declaringType, avaloniaProperty)
+            {
+                Parameters = new[] {types.UnsetValueType};
+            }
+
+            public override void Emit(IXamlIlEmitter codegen)
+            {
+                var unsetValue = Types.AvaloniaProperty.Fields.First(f => f.Name == "UnsetValue");
+                codegen
+                    // Ignore the instance and load one from the static field to avoid extra local variable
+                    .Pop()
+                    .Ldsfld(AvaloniaProperty)
+                    .Ldsfld(unsetValue)
+                    .Ldc_I4(0)
+                    .EmitCall(Types.AvaloniaObjectSetValueMethod, true);
+            }
+        }
+    }
+}

+ 9 - 0
src/Markup/Avalonia.Markup.Xaml/XamlIl/Runtime/IAvaloniaXamlIlParentStackProvider.cs

@@ -0,0 +1,9 @@
+using System.Collections.Generic;
+
+namespace Avalonia.Markup.Xaml.XamlIl.Runtime
+{
+    public interface IAvaloniaXamlIlParentStackProvider
+    {
+        IEnumerable<object> Parents { get; }
+    }
+}

+ 15 - 0
src/Markup/Avalonia.Markup.Xaml/XamlIl/Runtime/IAvaloniaXamlIlXmlNamespaceInfoProviderV1.cs

@@ -0,0 +1,15 @@
+using System.Collections.Generic;
+
+namespace Avalonia.Markup.Xaml.XamlIl.Runtime
+{
+    public interface IAvaloniaXamlIlXmlNamespaceInfoProvider
+    {
+        IReadOnlyDictionary<string, IReadOnlyList<AvaloniaXamlIlXmlNamespaceInfo>> XmlNamespaces { get; }
+    }
+    
+    public class AvaloniaXamlIlXmlNamespaceInfo
+    {
+        public string ClrNamespace { get; set; }
+        public string ClrAssemblyName { get; set; }
+    }
+}

+ 148 - 0
src/Markup/Avalonia.Markup.Xaml/XamlIl/Runtime/XamlIlRuntimeHelpers.cs

@@ -0,0 +1,148 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using Avalonia.Controls;
+using Avalonia.Data;
+using Portable.Xaml.Markup;
+// ReSharper disable UnusedMember.Global
+// ReSharper disable UnusedParameter.Global
+
+namespace Avalonia.Markup.Xaml.XamlIl.Runtime
+{
+    public static class XamlIlRuntimeHelpers
+    {
+        public static Func<IServiceProvider, object> DeferredTransformationFactoryV1(Func<IServiceProvider, object> builder,
+            IServiceProvider provider)
+        {
+            var resourceNodes = provider.GetService<IAvaloniaXamlIlParentStackProvider>().Parents
+                .OfType<IResourceNode>().ToList();
+
+            return sp => builder(new DeferredParentServiceProvider(sp, resourceNodes));
+        }
+
+        class DeferredParentServiceProvider : IAvaloniaXamlIlParentStackProvider, IServiceProvider
+        {
+            private readonly IServiceProvider _parentProvider;
+            private readonly List<IResourceNode> _parentResourceNodes;
+
+            public DeferredParentServiceProvider(IServiceProvider parentProvider, List<IResourceNode> parentResourceNodes)
+            {
+                _parentProvider = parentProvider;
+                _parentResourceNodes = parentResourceNodes;
+            }
+
+            public IEnumerable<object> Parents => GetParents();
+
+            IEnumerable<object> GetParents()
+            {
+                if(_parentResourceNodes == null)
+                    yield break;
+                foreach (var p in _parentResourceNodes)
+                    yield return p;
+            }
+
+            public object GetService(Type serviceType)
+            {
+                if (serviceType == typeof(IAvaloniaXamlIlParentStackProvider))
+                    return this;
+                return _parentProvider?.GetService(serviceType);
+            }
+        }
+
+
+        public static void ApplyNonMatchingMarkupExtensionV1(object target, object property, IServiceProvider prov,
+            object value)
+        {
+            if (value is IBinding b)
+            {
+                if (property is AvaloniaProperty p)
+                    ((AvaloniaObject)target).Bind(p, b);
+                else
+                    throw new ArgumentException("Attempt to apply binding to non-avalonia property " + property);
+            }
+            else if (value is UnsetValueType unset)
+            {
+                if (property is AvaloniaProperty p)
+                    ((AvaloniaObject)target).SetValue(p, unset);
+                //TODO: Investigate
+                //throw new ArgumentException("Attempt to apply UnsetValue to non-avalonia property " + property);
+            }
+            else
+                throw new ArgumentException("Don't know what to do with " + value.GetType());
+        }
+
+        public static IServiceProvider CreateInnerServiceProviderV1(IServiceProvider compiled) 
+            => new InnerServiceProvider(compiled);
+       
+        class InnerServiceProvider : IServiceProvider
+        {
+            private readonly IServiceProvider _compiledProvider;
+            private XamlTypeResolver _resolver;
+
+            public InnerServiceProvider(IServiceProvider compiledProvider)
+            {
+                _compiledProvider = compiledProvider;
+            }
+            public object GetService(Type serviceType)
+            {
+                if (serviceType == typeof(IXamlTypeResolver))
+                    return _resolver ?? (_resolver = new XamlTypeResolver(
+                               _compiledProvider.GetService<IAvaloniaXamlIlXmlNamespaceInfoProvider>()));
+                return null;
+            }
+        }
+
+        class XamlTypeResolver : IXamlTypeResolver
+        {
+            private readonly IAvaloniaXamlIlXmlNamespaceInfoProvider _nsInfo;
+
+            public XamlTypeResolver(IAvaloniaXamlIlXmlNamespaceInfoProvider nsInfo)
+            {
+                _nsInfo = nsInfo;
+            }
+            
+            public Type Resolve(string qualifiedTypeName)
+            {
+                var sp = qualifiedTypeName.Split(new[] {':'}, 2);
+                var (ns, name) = sp.Length == 1 ? ("", qualifiedTypeName) : (sp[0], sp[1]);
+                var namespaces = _nsInfo.XmlNamespaces;
+                var dic = (Dictionary<string, IReadOnlyList<AvaloniaXamlIlXmlNamespaceInfo>>)namespaces;
+                if (!namespaces.TryGetValue(ns, out var lst))
+                    throw new ArgumentException("Unable to resolve namespace for type " + qualifiedTypeName);
+                foreach (var entry in lst)
+                {
+                    var asm = Assembly.Load(new AssemblyName(entry.ClrAssemblyName));
+                    var resolved = asm.GetType(entry.ClrNamespace + "." + name);
+                    if (resolved != null)
+                        return resolved;
+                }
+
+                throw new ArgumentException(
+                    $"Unable to resolve type {qualifiedTypeName} from any of the following locations: " +
+                    string.Join(",", lst.Select(e => $"`{e.ClrAssemblyName}:{e.ClrNamespace}.{name}`")));
+            }
+        }
+        
+        public static readonly IServiceProvider RootServiceProviderV1 = new RootServiceProvider();
+
+        class RootServiceProvider : IServiceProvider, IAvaloniaXamlIlParentStackProvider
+        {
+            public object GetService(Type serviceType)
+            {
+                if (serviceType == typeof(IAvaloniaXamlIlParentStackProvider))
+                    return this;
+                return null;
+            }
+
+            public IEnumerable<object> Parents
+            {
+                get
+                {
+                    if (Application.Current != null)
+                        yield return Application.Current;
+                }
+            }
+        }
+    }
+}

+ 1 - 0
src/Markup/Avalonia.Markup.Xaml/XamlIl/xamlil.github

@@ -0,0 +1 @@
+Subproject commit 3b3c1f93a566080d417b9782f9cc4ea67cd62344

+ 1 - 1
src/Markup/Avalonia.Markup/Data/MultiBinding.cs

@@ -19,7 +19,7 @@ namespace Avalonia.Data
         /// <summary>
         /// Gets the collection of child bindings.
         /// </summary>
-        [Content]
+        [Content, AssignBinding]
         public IList<IBinding> Bindings { get; set; } = new List<IBinding>();
 
         /// <summary>

+ 2 - 0
src/Markup/Avalonia.Markup/Data/TemplateBinding.cs

@@ -183,5 +183,7 @@ namespace Avalonia.Data
                 PublishValue();
             }
         }
+
+        public IBinding ProvideValue() => this;
     }
 }

+ 1 - 1
src/Markup/Avalonia.Markup/Markup/Parsers/SelectorGrammar.cs

@@ -275,7 +275,7 @@ namespace Avalonia.Markup.Parsers
         private static TSyntax ParseType<TSyntax>(ref CharacterReader r, TSyntax syntax)
             where TSyntax : ITypeSyntax
         {
-            ReadOnlySpan<char> ns = null;
+            ReadOnlySpan<char> ns = default;
             ReadOnlySpan<char> type;
             var namespaceOrTypeName = r.ParseIdentifier();
 

+ 7 - 0
src/Shared/PlatformSupport/AssetLoader.cs

@@ -97,6 +97,13 @@ namespace Avalonia.Shared.PlatformSupport
             return (asset.GetStream(), asset.Assembly);
         }
 
+        public Assembly GetAssembly(Uri uri, Uri baseUri)
+        {
+            if (!uri.IsAbsoluteUri && baseUri != null)
+                uri = new Uri(baseUri, uri);
+            return GetAssembly(uri).Assembly;
+        }
+
         /// <summary>
         /// Gets all assets of a folder and subfolders that match specified uri.
         /// </summary>

+ 2 - 5
tests/Avalonia.Markup.Xaml.UnitTests/Avalonia.Markup.Xaml.UnitTests.csproj

@@ -29,13 +29,10 @@
     <EmbeddedResource Include="Xaml\Style1.xaml">
       <SubType>Designer</SubType>
     </EmbeddedResource>
-  </ItemGroup>
-  <ItemGroup>
     <EmbeddedResource Include="Xaml\Style2.xaml">
       <SubType>Designer</SubType>
     </EmbeddedResource>
+    <AvaloniaResource Include="Xaml\XamlIlClassWithPrecompiledXaml.xaml"/>
   </ItemGroup>
-  <ItemGroup>
-    <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
-  </ItemGroup>
+  <Import Project="..\..\build\BuildTargets.targets" />
 </Project>

+ 1 - 1
tests/Avalonia.Markup.Xaml.UnitTests/StyleTests.cs

@@ -19,7 +19,7 @@ namespace Avalonia.Markup.Xaml.UnitTests
         {
             using (UnitTestApplication.Start(TestServices.MockPlatformWrapper))
             {
-                var xaml = "<Style xmlns='https://github.com/avaloniaui'><Setter Value='{Binding}'/></Style>";
+                var xaml = "<Style Selector='Button' xmlns='https://github.com/avaloniaui'><Setter Property='Content' Value='{Binding}'/></Style>";
                 var loader = new AvaloniaXamlLoader();
                 var style = (Style)loader.Load(xaml);
                 var setter = (Setter)(style.Setters.First());

+ 18 - 4
tests/Avalonia.Markup.Xaml.UnitTests/Xaml/BasicTests.cs

@@ -1,6 +1,7 @@
 // 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 Avalonia.Collections;
 using Avalonia.Controls;
 using Avalonia.Controls.Presenters;
@@ -17,6 +18,7 @@ using Portable.Xaml;
 using System.Collections;
 using System.ComponentModel;
 using System.Linq;
+using System.Xml;
 using Xunit;
 
 namespace Avalonia.Markup.Xaml.UnitTests.Xaml
@@ -48,6 +50,9 @@ namespace Avalonia.Markup.Xaml.UnitTests.Xaml
         [Fact]
         public void AvaloniaProperty_Without_Getter_And_Setter_Is_Set()
         {
+            // It's not possible to know in compile time if a read-only property has a magic way of being not read-only
+            if (!AvaloniaXamlLoader.UseLegacyXamlLoader)
+                return;
             var xaml =
  @"<local:NonControl xmlns='https://github.com/avaloniaui' 
     xmlns:local='clr-namespace:Avalonia.Markup.Xaml.UnitTests.Xaml;assembly=Avalonia.Markup.Xaml.UnitTests'
@@ -61,6 +66,8 @@ namespace Avalonia.Markup.Xaml.UnitTests.Xaml
         [Fact]
         public void AvaloniaProperty_With_Getter_And_No_Setter_Is_Set()
         {
+            if(!AvaloniaXamlLoader.UseLegacyXamlLoader)
+                return;
             var xaml =
 @"<local:NonControl xmlns='https://github.com/avaloniaui' 
     xmlns:local='clr-namespace:Avalonia.Markup.Xaml.UnitTests.Xaml;assembly=Avalonia.Markup.Xaml.UnitTests'
@@ -142,23 +149,27 @@ namespace Avalonia.Markup.Xaml.UnitTests.Xaml
 
             Assert.Equal("Foo", ToolTip.GetTip(target));
         }
-
+        
         [Fact]
         public void NonExistent_Property_Throws()
         {
             var xaml =
         @"<ContentControl xmlns='https://github.com/avaloniaui' DoesntExist='foo'/>";
 
-            Assert.Throws<XamlObjectWriterException>(() => AvaloniaXamlLoader.Parse<ContentControl>(xaml));
+            XamlTestHelpers.AssertThrowsXamlException(() => AvaloniaXamlLoader.Parse<ContentControl>(xaml));
         }
 
         [Fact]
         public void Non_Attached_Property_With_Attached_Property_Syntax_Throws()
         {
+            // 1) It has been allowed in AvaloniaObject.SetValue for ages
+            // 2) There is no way to know if AddOwner was called in compile-time
+            if (!AvaloniaXamlLoader.UseLegacyXamlLoader)
+                return;
             var xaml =
         @"<ContentControl xmlns='https://github.com/avaloniaui' TextBlock.Text='foo'/>";
 
-            Assert.Throws<XamlObjectWriterException>(() => AvaloniaXamlLoader.Parse<ContentControl>(xaml));
+            XamlTestHelpers.AssertThrowsXamlException(() => AvaloniaXamlLoader.Parse<ContentControl>(xaml));
         }
 
         [Fact]
@@ -518,7 +529,7 @@ namespace Avalonia.Markup.Xaml.UnitTests.Xaml
             var xaml = @"
 <Style xmlns='https://github.com/avaloniaui'
         xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
-        xmlns:sys='clr-namespace:System;assembly=mscorlib'>
+        xmlns:sys='clr-namespace:System;assembly=netstandard'>
     <Style.Resources>
         <SolidColorBrush x:Key='Brush'>White</SolidColorBrush>
         <sys:Double x:Key='Double'>10</sys:Double>
@@ -587,6 +598,9 @@ namespace Avalonia.Markup.Xaml.UnitTests.Xaml
         [Fact]
         public void Xaml_Binding_Is_Delayed()
         {
+            if (!AvaloniaXamlLoader.UseLegacyXamlLoader)
+                return;
+            
             using (UnitTestApplication.Start(TestServices.MockWindowingPlatform))
             {
                 var xaml =

+ 1 - 1
tests/Avalonia.Markup.Xaml.UnitTests/Xaml/DataTemplateTests.cs

@@ -17,7 +17,7 @@ namespace Avalonia.Markup.Xaml.UnitTests.Xaml
             {
                 var xaml = @"
 <Window xmlns='https://github.com/avaloniaui'
-        xmlns:sys='clr-namespace:System;assembly=mscorlib'
+        xmlns:sys='clr-namespace:System;assembly=netstandard'
         xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
     <Window.DataTemplates>
         <DataTemplate DataType='{x:Type sys:String}'>

+ 7 - 3
tests/Avalonia.Markup.Xaml.UnitTests/Xaml/EventTests.cs

@@ -4,6 +4,7 @@
 using System;
 using Avalonia.Controls;
 using Avalonia.Input;
+using Avalonia.Interactivity;
 using Portable.Xaml;
 using Xunit;
 
@@ -31,12 +32,15 @@ namespace Avalonia.Markup.Xaml.UnitTests.Xaml
             var loader = new AvaloniaXamlLoader();
             var target = new MyButton();
 
-            Assert.Throws<XamlObjectWriterException>(() => loader.Load(xaml, rootInstance: target));
+            XamlTestHelpers.AssertThrowsXamlException(() => loader.Load(xaml, rootInstance: target));
         }
 
         [Fact]
         public void Exception_Is_Not_Thrown_If_Event_Not_Found_In_Design_Mode()
         {
+            // Runtime compiler should properly understand x:Class
+            if (!AvaloniaXamlLoader.UseLegacyXamlLoader)
+                return;
             var xaml = @"<Button xmlns='https://github.com/avaloniaui' Click='NotFound'/>";
             var loader = new AvaloniaXamlLoader { IsDesignMode = true };
             var target = new MyButton();
@@ -53,11 +57,11 @@ namespace Avalonia.Markup.Xaml.UnitTests.Xaml
             });
         }
 
-        class MyButton : Button
+        public class MyButton : Button
         {
             public bool Clicked { get; private set; }
 
-            public void OnClick(object sender, EventArgs e)
+            public void OnClick(object sender, RoutedEventArgs e)
             {
                 Clicked = true;
             }

+ 3 - 2
tests/Avalonia.Markup.Xaml.UnitTests/Xaml/Style1.xaml

@@ -1,8 +1,9 @@
 <Style xmlns="https://github.com/avaloniaui"
-       xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
+       xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+       x:Precompile="False">
   <Style.Resources>
     <Color x:Key="Red">Red</Color>
     <Color x:Key="Green">Green</Color>
     <Color x:Key="Blue">Blue</Color>
   </Style.Resources>
-</Style>
+</Style>

+ 3 - 2
tests/Avalonia.Markup.Xaml.UnitTests/Xaml/Style2.xaml

@@ -1,8 +1,9 @@
 <Style xmlns="https://github.com/avaloniaui"
-       xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
+       xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+       x:Precompile="False">
   <Style.Resources>
     <SolidColorBrush x:Key="RedBrush" Color="{DynamicResource Red}"/>
     <SolidColorBrush x:Key="GreenBrush" Color="{DynamicResource Green}"/>
     <SolidColorBrush x:Key="BlueBrush" Color="{DynamicResource Blue}"/>
   </Style.Resources>
-</Style>
+</Style>

+ 6 - 0
tests/Avalonia.Markup.Xaml.UnitTests/Xaml/XamlIlClassWithPrecompiledXaml.xaml

@@ -0,0 +1,6 @@
+<UserControl xmlns='https://github.com/avaloniaui'
+             xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
+             x:Class='Avalonia.Markup.Xaml.UnitTests.XamlIlClassWithPrecompiledXaml'
+             Background="Red">
+    
+</UserControl>

+ 146 - 0
tests/Avalonia.Markup.Xaml.UnitTests/Xaml/XamlIlTests.cs

@@ -0,0 +1,146 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Globalization;
+using System.Linq;
+using System.Runtime.CompilerServices;
+using Avalonia.Controls;
+using Avalonia.Data.Converters;
+using Avalonia.Media;
+using Avalonia.UnitTests;
+using Avalonia.VisualTree;
+using JetBrains.Annotations;
+using Xunit;
+
+namespace Avalonia.Markup.Xaml.UnitTests
+{
+    public class XamlIlTests
+    {
+        [Fact]
+        public void Binding_Button_IsPressed_ShouldWork()
+        {
+            var parsed = (Button)AvaloniaXamlLoader.Parse(@"
+<Button xmlns='https://github.com/avaloniaui' IsPressed='{Binding IsPressed, Mode=TwoWay}' />");
+            var ctx = new XamlIlBugTestsDataContext();
+            parsed.DataContext = ctx;
+            parsed.SetValue(Button.IsPressedProperty, true);
+            Assert.True(ctx.IsPressed);
+        }
+
+        [Fact]
+        public void Transitions_Should_Be_Properly_Parsed()
+        {
+            var parsed = (Grid)AvaloniaXamlLoader.Parse(@"
+<Grid xmlns='https://github.com/avaloniaui' >
+  <Grid.Transitions>
+    <DoubleTransition Property='Opacity'
+       Easing='CircularEaseIn'
+       Duration='0:0:0.5' />
+  </Grid.Transitions>
+</Grid>");
+            Assert.Equal(1, parsed.Transitions.Count);
+            Assert.Equal(Visual.OpacityProperty, parsed.Transitions[0].Property);
+        }
+
+        [Fact]
+        public void Parser_Should_Override_Precompiled_Xaml()
+        {
+            var precompiled = new XamlIlClassWithPrecompiledXaml();
+            Assert.Equal(Brushes.Red, precompiled.Background);
+            Assert.Equal(1, precompiled.Opacity);
+            var loaded = (XamlIlClassWithPrecompiledXaml)AvaloniaXamlLoader.Parse(@"
+<UserControl xmlns='https://github.com/avaloniaui'
+             xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
+             x:Class='Avalonia.Markup.Xaml.UnitTests.XamlIlClassWithPrecompiledXaml'
+             Opacity='0'>
+    
+</UserControl>");
+            Assert.Equal(loaded.Opacity, 0);
+            Assert.Null(loaded.Background);
+            
+        }
+
+        [Fact]
+        public void RelativeSource_TemplatedParent_Works()
+        {
+            using (UnitTestApplication.Start(TestServices.StyledWindow))
+            {
+                new AvaloniaXamlLoader().Load(@"
+<Application
+  xmlns='https://github.com/avaloniaui'
+  xmlns:local='clr-namespace:Avalonia.Markup.Xaml.UnitTests;assembly=Avalonia.Markup.Xaml.UnitTests'
+>
+<Application.Styles>
+    <Style Selector='Button'>
+      <Setter Property='Template'>
+        <ControlTemplate>
+          <Grid><Grid><Grid>
+            <Canvas>
+              <Canvas.Background>
+                <SolidColorBrush>
+                  <SolidColorBrush.Color>
+                    <MultiBinding>
+                      <MultiBinding.Converter>
+                          <local:XamlIlBugTestsBrushToColorConverter/>
+                      </MultiBinding.Converter>
+                      <Binding Path='Background' RelativeSource='{RelativeSource TemplatedParent}'/>
+                      <Binding Path='Background' RelativeSource='{RelativeSource TemplatedParent}'/>
+                      <Binding Path='Background' RelativeSource='{RelativeSource TemplatedParent}'/>
+                    </MultiBinding>
+                  </SolidColorBrush.Color>
+                </SolidColorBrush>
+              </Canvas.Background>
+            </Canvas>
+          </Grid></Grid></Grid>
+        </ControlTemplate>
+      </Setter>
+    </Style>
+  </Application.Styles>
+</Application>",
+                    null, Application.Current); 
+                var parsed = (Window)AvaloniaXamlLoader.Parse(@"
+<Window
+  xmlns='https://github.com/avaloniaui'
+  xmlns:local='clr-namespace:Avalonia.Markup.Xaml.UnitTests;assembly=Avalonia.Markup.Xaml.UnitTests'
+>
+  
+  <Button Background='Red' />
+
+</Window>
+");
+                var btn = ((Button)parsed.Content);
+                btn.ApplyTemplate();
+                var canvas = (Canvas)btn.GetVisualChildren().First()
+                    .VisualChildren.First()
+                    .VisualChildren.First()
+                    .VisualChildren.First();
+                Assert.Equal(Brushes.Red.Color, ((ISolidColorBrush)canvas.Background).Color);
+            }
+        }
+    }
+
+    public class XamlIlBugTestsBrushToColorConverter : IMultiValueConverter
+    {
+        public object Convert(IList<object> values, Type targetType, object parameter, CultureInfo culture)
+        {
+            return (values[0] as ISolidColorBrush)?.Color;
+        }
+    }
+
+    public class XamlIlBugTestsDataContext : INotifyPropertyChanged
+    {
+        public bool IsPressed { get; set; }
+        public event PropertyChangedEventHandler PropertyChanged;
+
+        [NotifyPropertyChangedInvocator]
+        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
+        {
+            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
+        }
+    }
+
+    public class XamlIlClassWithPrecompiledXaml : UserControl
+    {
+    }
+
+}

+ 23 - 0
tests/Avalonia.Markup.Xaml.UnitTests/Xaml/XamlTestHelpers.cs

@@ -0,0 +1,23 @@
+using System;
+using System.Xml;
+using Portable.Xaml;
+
+namespace Avalonia.Markup.Xaml.UnitTests.Xaml
+{
+    public class XamlTestHelpers
+    {
+        public static void AssertThrowsXamlException(Action cb)
+        {
+            try
+            {
+                cb();
+            }
+            catch (Exception e)
+            {
+                if(e is XamlObjectWriterException || e is XmlException)
+                    return;
+            }
+            throw new Exception("Expected to throw xaml exception");
+        }
+    }
+}

+ 5 - 0
tests/Avalonia.UnitTests/MockAssetLoader.cs

@@ -32,6 +32,11 @@ namespace Avalonia.UnitTests
             return (Open(uri, baseUri), (Assembly)null);
         }
 
+        public Assembly GetAssembly(Uri uri, Uri baseUri = null)
+        {
+            return null;
+        }
+
         public IEnumerable<Uri> GetAssets(Uri uri, Uri baseUri)
         {
             return _assets.Keys.Where(x => x.AbsolutePath.Contains(uri.AbsolutePath));

+ 5 - 0
tests/Avalonia.UnitTests/UnitTestApplication.cs

@@ -19,6 +19,11 @@ namespace Avalonia.UnitTests
     {
         private readonly TestServices _services;
 
+        public UnitTestApplication() : this(null)
+        {
+            
+        }
+        
         public UnitTestApplication(TestServices services)
         {
             _services = services ?? new TestServices();