diff --git a/packages/Avalonia/AvaloniaBuildTasks.targets b/packages/Avalonia/AvaloniaBuildTasks.targets
index 4b9e33ffe8..01bf303a20 100644
--- a/packages/Avalonia/AvaloniaBuildTasks.targets
+++ b/packages/Avalonia/AvaloniaBuildTasks.targets
@@ -4,6 +4,7 @@
<_AvaloniaUseExternalMSBuild Condition="'$(_AvaloniaForceInternalMSBuild)' == 'true'">false
low
<_AvaloniaSkipXamlCompilation Condition="'$(_AvaloniaSkipXamlCompilation)' == ''">false
+ false
@@ -43,7 +44,7 @@
$(BuildAvaloniaResourcesDependsOn);AddAvaloniaResources;ResolveReferences;_GenerateAvaloniaResourcesDependencyCache
-
+
@@ -106,6 +107,7 @@
DelaySign="$(DelaySign)"
SkipXamlCompilation="$(_AvaloniaSkipXamlCompilation)"
DebuggerLaunch="$(AvaloniaXamlIlDebuggerLaunch)"
+ DefaultCompileBindings="$(AvaloniaUseCompiledBindingsByDefault)"
/>
!string.IsNullOrWhiteSpace(l)).ToArray(),
- ProjectDirectory, OutputPath, VerifyIl, outputImportance,
+ ProjectDirectory, OutputPath, VerifyIl, DefaultCompileBindings, outputImportance,
(SignAssembly && !DelaySign) ? AssemblyOriginatorKeyFile : null, SkipXamlCompilation, DebuggerLaunch);
if (!res.Success)
return false;
@@ -71,6 +71,9 @@ namespace Avalonia.Build.Tasks
public string OutputPath { get; set; }
public bool VerifyIl { get; set; }
+
+ public bool DefaultCompileBindings { get; set; }
+
public bool SkipXamlCompilation { get; set; }
public string AssemblyOriginatorKeyFile { get; set; }
diff --git a/src/Avalonia.Build.Tasks/XamlCompilerTaskExecutor.cs b/src/Avalonia.Build.Tasks/XamlCompilerTaskExecutor.cs
index 97aa8abc2f..3493fc06ed 100644
--- a/src/Avalonia.Build.Tasks/XamlCompilerTaskExecutor.cs
+++ b/src/Avalonia.Build.Tasks/XamlCompilerTaskExecutor.cs
@@ -39,43 +39,52 @@ namespace Avalonia.Build.Tasks
public static CompileResult Compile(IBuildEngine engine, string input, string[] references,
string projectDirectory,
- string output, bool verifyIl, MessageImportance logImportance, string strongNameKey,
+ string output, bool verifyIl, bool defaultCompileBindings, MessageImportance logImportance, string strongNameKey,
bool skipXamlCompilation)
{
- return Compile(engine, input, references, projectDirectory, output, verifyIl, logImportance, strongNameKey, skipXamlCompilation, debuggerLaunch:false);
+ return Compile(engine, input, references, projectDirectory, output, verifyIl, defaultCompileBindings, logImportance, strongNameKey, skipXamlCompilation, debuggerLaunch:false);
}
internal static CompileResult Compile(IBuildEngine engine, string input, string[] references,
string projectDirectory,
- string output, bool verifyIl, MessageImportance logImportance, string strongNameKey, bool skipXamlCompilation, bool debuggerLaunch)
+ string output, bool verifyIl, bool defaultCompileBindings, MessageImportance logImportance, string strongNameKey, bool skipXamlCompilation, bool debuggerLaunch)
{
- var typeSystem = new CecilTypeSystem(
- references.Where(r => !r.ToLowerInvariant().EndsWith("avalonia.build.tasks.dll")),
- input);
-
- var asm = typeSystem.TargetAssemblyDefinition;
-
- if (!skipXamlCompilation)
+ try
{
- var compileRes = CompileCore(engine, typeSystem, projectDirectory, verifyIl, logImportance, debuggerLaunch);
- if (compileRes == null)
- return new CompileResult(true);
- if (compileRes == false)
- return new CompileResult(false);
- }
+ var typeSystem = new CecilTypeSystem(
+ references.Where(r => !r.ToLowerInvariant().EndsWith("avalonia.build.tasks.dll")),
+ input);
- var writerParameters = new WriterParameters { WriteSymbols = asm.MainModule.HasSymbols };
- if (!string.IsNullOrWhiteSpace(strongNameKey))
- writerParameters.StrongNameKeyBlob = File.ReadAllBytes(strongNameKey);
+ var asm = typeSystem.TargetAssemblyDefinition;
+
+ if (!skipXamlCompilation)
+ {
+ var compileRes = CompileCore(engine, typeSystem, projectDirectory, verifyIl, defaultCompileBindings,
+ logImportance, debuggerLaunch);
+ if (compileRes == null)
+ return new CompileResult(true);
+ if (compileRes == false)
+ return new CompileResult(false);
+ }
- asm.Write(output, writerParameters);
+ var writerParameters = new WriterParameters { WriteSymbols = asm.MainModule.HasSymbols };
+ if (!string.IsNullOrWhiteSpace(strongNameKey))
+ writerParameters.StrongNameKeyBlob = File.ReadAllBytes(strongNameKey);
- return new CompileResult(true, true);
+ asm.Write(output, writerParameters);
+ return new CompileResult(true, true);
+ }
+ catch (Exception ex)
+ {
+ engine.LogError(BuildEngineErrorCode.Unknown, "", ex.Message);
+ return new CompileResult(false);
+ }
}
static bool? CompileCore(IBuildEngine engine, CecilTypeSystem typeSystem,
- string projectDirectory, bool verifyIl,
+ string projectDirectory, bool verifyIl,
+ bool defaultCompileBindings,
MessageImportance logImportance
, bool debuggerLaunch = false)
{
@@ -113,7 +122,16 @@ namespace Avalonia.Build.Tasks
if (avares.Resources.Count(CheckXamlName) == 0)
// Nothing to do
return null;
-
+ if (typeSystem.FindType("System.Reflection.AssemblyMetadataAttribute") is {} asmMetadata)
+ {
+ var ctor = asm.MainModule.ImportReference(typeSystem.GetTypeReference(asmMetadata).Resolve()
+ .GetConstructors().First(c => c.Parameters.Count == 2).Resolve());
+ var strType = asm.MainModule.ImportReference(typeof(string));
+ var arg1 = new CustomAttributeArgument(strType, "AvaloniaUseCompiledBindingsByDefault");
+ var arg2 = new CustomAttributeArgument(strType, defaultCompileBindings.ToString());
+ asm.CustomAttributes.Add(new CustomAttribute(ctor) { ConstructorArguments = { arg1, arg2 } });
+ }
+
var clrPropertiesDef = new TypeDefinition("CompiledAvaloniaXaml", "XamlIlHelpers",
TypeAttributes.Class, asm.MainModule.TypeSystem.Object);
asm.MainModule.Types.Add(clrPropertiesDef);
@@ -143,7 +161,7 @@ namespace Avalonia.Build.Tasks
var contextClass = XamlILContextDefinition.GenerateContextClass(typeSystem.CreateTypeBuilder(contextDef), typeSystem,
xamlLanguage, emitConfig);
- var compiler = new AvaloniaXamlIlCompiler(compilerConfig, emitConfig, contextClass) { EnableIlVerification = verifyIl };
+ var compiler = new AvaloniaXamlIlCompiler(compilerConfig, emitConfig, contextClass) { EnableIlVerification = verifyIl, DefaultCompileBindings = defaultCompileBindings };
var editorBrowsableAttribute = typeSystem
.GetTypeReference(typeSystem.FindType("System.ComponentModel.EditorBrowsableAttribute"))
diff --git a/src/Avalonia.DesignerSupport/DesignWindowLoader.cs b/src/Avalonia.DesignerSupport/DesignWindowLoader.cs
index 811f9c7baa..9a901f909a 100644
--- a/src/Avalonia.DesignerSupport/DesignWindowLoader.cs
+++ b/src/Avalonia.DesignerSupport/DesignWindowLoader.cs
@@ -35,7 +35,16 @@ namespace Avalonia.DesignerSupport
}
var localAsm = assemblyPath != null ? Assembly.LoadFile(Path.GetFullPath(assemblyPath)) : null;
- var loaded = loader.Load(stream, localAsm, null, baseUri, true);
+ var useCompiledBindings = localAsm?.GetCustomAttributes()
+ .FirstOrDefault(a => a.Key == "AvaloniaUseCompiledBindingsByDefault")?.Value;
+
+ var loaded = loader.Load(stream, new RuntimeXamlLoaderConfiguration
+ {
+ LocalAssembly = localAsm,
+ BaseUri = baseUri,
+ DesignMode = true,
+ UseCompiledBindingsByDefault = bool.TryParse(useCompiledBindings, out var parsedValue ) && parsedValue
+ });
var style = loaded as IStyle;
var resources = loaded as ResourceDictionary;
if (style != null)
diff --git a/src/Markup/Avalonia.Markup.Xaml.Loader/AvaloniaRuntimeXamlLoader.cs b/src/Markup/Avalonia.Markup.Xaml.Loader/AvaloniaRuntimeXamlLoader.cs
index 4df07bcdd8..9393bb0aa4 100644
--- a/src/Markup/Avalonia.Markup.Xaml.Loader/AvaloniaRuntimeXamlLoader.cs
+++ b/src/Markup/Avalonia.Markup.Xaml.Loader/AvaloniaRuntimeXamlLoader.cs
@@ -26,6 +26,22 @@ namespace Avalonia.Markup.Xaml
return Load(stream, localAssembly, rootInstance, uri, designMode);
}
}
+
+ ///
+ /// Loads XAML from a string.
+ ///
+ /// The string containing the XAML.
+ /// Xaml loader configuration.
+ /// The loaded object.
+ public static object Load(string xaml, RuntimeXamlLoaderConfiguration configuration)
+ {
+ Contract.Requires(xaml != null);
+
+ using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(xaml)))
+ {
+ return Load(stream, configuration);
+ }
+ }
///
/// Loads XAML from a stream.
@@ -38,7 +54,17 @@ namespace Avalonia.Markup.Xaml
/// The loaded object.
public static object Load(Stream stream, Assembly localAssembly, object rootInstance = null, Uri uri = null,
bool designMode = false)
- => AvaloniaXamlIlRuntimeCompiler.Load(stream, localAssembly, rootInstance, uri, designMode);
+ => AvaloniaXamlIlRuntimeCompiler.Load(stream, localAssembly, rootInstance, uri, designMode, false);
+
+ ///
+ /// Loads XAML from a stream.
+ ///
+ /// The stream containing the XAML.
+ /// Xaml loader configuration.
+ /// The loaded object.
+ public static object Load(Stream stream, RuntimeXamlLoaderConfiguration configuration)
+ => AvaloniaXamlIlRuntimeCompiler.Load(stream, configuration.LocalAssembly, configuration.RootInstance,
+ configuration.BaseUri, configuration.DesignMode, configuration.UseCompiledBindingsByDefault);
///
/// Parse XAML from a string.
diff --git a/src/Markup/Avalonia.Markup.Xaml.Loader/AvaloniaXamlIlRuntimeCompiler.cs b/src/Markup/Avalonia.Markup.Xaml.Loader/AvaloniaXamlIlRuntimeCompiler.cs
index 1d4794f02a..b4b258e53e 100644
--- a/src/Markup/Avalonia.Markup.Xaml.Loader/AvaloniaXamlIlRuntimeCompiler.cs
+++ b/src/Markup/Avalonia.Markup.Xaml.Loader/AvaloniaXamlIlRuntimeCompiler.cs
@@ -150,12 +150,12 @@ namespace Avalonia.Markup.Xaml.XamlIl
}
- static object LoadSre(string xaml, Assembly localAssembly, object rootInstance, Uri uri, bool isDesignMode)
+ static object LoadSre(string xaml, Assembly localAssembly, object rootInstance, Uri uri, bool isDesignMode, bool useCompiledBindingsByDefault)
{
var success = false;
try
{
- var rv = LoadSreCore(xaml, localAssembly, rootInstance, uri, isDesignMode);
+ var rv = LoadSreCore(xaml, localAssembly, rootInstance, uri, isDesignMode, useCompiledBindingsByDefault);
success = true;
return rv;
}
@@ -167,7 +167,7 @@ namespace Avalonia.Markup.Xaml.XamlIl
}
- static object LoadSreCore(string xaml, Assembly localAssembly, object rootInstance, Uri uri, bool isDesignMode)
+ static object LoadSreCore(string xaml, Assembly localAssembly, object rootInstance, Uri uri, bool isDesignMode, bool useCompiledBindingsByDefault)
{
InitializeSre();
@@ -178,15 +178,14 @@ namespace Avalonia.Markup.Xaml.XamlIl
var clrPropertyBuilder = tb.DefineNestedType("ClrProperties_" + Guid.NewGuid().ToString("N"));
var indexerClosureType = _sreBuilder.DefineType("IndexerClosure_" + Guid.NewGuid().ToString("N"));
var trampolineBuilder = _sreBuilder.DefineType("Trampolines_" + Guid.NewGuid().ToString("N"));
-
+
var compiler = new AvaloniaXamlIlCompiler(new AvaloniaXamlIlCompilerConfiguration(_sreTypeSystem, asm,
_sreMappings, _sreXmlns, AvaloniaXamlIlLanguage.CustomValueConverter,
new XamlIlClrPropertyInfoEmitter(_sreTypeSystem.CreateTypeBuilder(clrPropertyBuilder)),
new XamlIlPropertyInfoAccessorFactoryEmitter(_sreTypeSystem.CreateTypeBuilder(indexerClosureType)),
new XamlIlTrampolineBuilder(_sreTypeSystem.CreateTypeBuilder(trampolineBuilder))),
_sreEmitMappings,
- _sreContextType) { EnableIlVerification = true };
-
+ _sreContextType) { EnableIlVerification = true, DefaultCompileBindings = useCompiledBindingsByDefault };
IXamlType overrideType = null;
if (rootInstance != null)
@@ -204,8 +203,8 @@ namespace Avalonia.Markup.Xaml.XamlIl
return LoadOrPopulate(created, rootInstance);
}
#endif
-
- static object LoadOrPopulate(Type created, object rootInstance)
+
+ static object LoadOrPopulate(Type created, object rootInstance)
{
var isp = Expression.Parameter(typeof(IServiceProvider));
@@ -251,15 +250,15 @@ namespace Avalonia.Markup.Xaml.XamlIl
}
public static object Load(Stream stream, Assembly localAssembly, object rootInstance, Uri uri,
- bool isDesignMode)
+ bool isDesignMode, bool useCompiledBindingsByDefault)
{
string xaml;
using (var sr = new StreamReader(stream))
xaml = sr.ReadToEnd();
#if RUNTIME_XAML_CECIL
- return LoadCecil(xaml, localAssembly, rootInstance, uri);
+ return LoadCecil(xaml, localAssembly, rootInstance, uri, useCompiledBindingsByDefault);
#else
- return LoadSre(xaml, localAssembly, rootInstance, uri, isDesignMode);
+ return LoadSre(xaml, localAssembly, rootInstance, uri, isDesignMode, useCompiledBindingsByDefault);
#endif
}
@@ -293,7 +292,7 @@ namespace Avalonia.Markup.Xaml.XamlIl
}
private static Dictionary _cecilGeneratedCache = new Dictionary();
- static object LoadCecil(string xaml, Assembly localAssembly, object rootInstance, Uri uri)
+ static object LoadCecil(string xaml, Assembly localAssembly, object rootInstance, Uri uri, bool useCompiledBindingsByDefault)
{
if (uri == null)
throw new InvalidOperationException("Please, go away");
@@ -303,8 +302,6 @@ namespace Avalonia.Markup.Xaml.XamlIl
{
overrideType = _cecilTypeSystem.GetType(rootInstance.GetType().FullName);
}
-
-
var safeUri = uri.ToString()
.Replace(":", "_")
@@ -328,13 +325,16 @@ namespace Avalonia.Markup.Xaml.XamlIl
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),
_cecilEmitMappings,
- _cecilTypeSystem.CreateTypeBuilder(contextDef));
+ _cecilTypeSystem.CreateTypeBuilder(contextDef))
+ {
+ DefaultCompileBindings = useCompiledBindingsByDefault
+ };
compiler.ParseAndCompile(xaml, uri.ToString(), tb, overrideType);
var asmPath = Path.Combine(_cecilEmitDir, safeUri + ".dll");
using(var f = File.Create(asmPath))
diff --git a/src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj b/src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj
index f5bf14c2a4..070f0c1cc3 100644
--- a/src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj
+++ b/src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj
@@ -44,6 +44,7 @@
+
diff --git a/src/Markup/Avalonia.Markup.Xaml/AvaloniaXamlLoader.cs b/src/Markup/Avalonia.Markup.Xaml/AvaloniaXamlLoader.cs
index e5c6b72d12..578af64abb 100644
--- a/src/Markup/Avalonia.Markup.Xaml/AvaloniaXamlLoader.cs
+++ b/src/Markup/Avalonia.Markup.Xaml/AvaloniaXamlLoader.cs
@@ -1,8 +1,5 @@
using System;
using System.IO;
-using System.Reflection;
-using System.Text;
-using Avalonia.Markup.Xaml.XamlIl;
using Avalonia.Platform;
namespace Avalonia.Markup.Xaml
@@ -14,7 +11,7 @@ namespace Avalonia.Markup.Xaml
{
public interface IRuntimeXamlLoader
{
- object Load(Stream stream, Assembly localAsm, object o, Uri baseUri, bool designMode);
+ object Load(Stream stream, RuntimeXamlLoaderConfiguration configuration);
}
///
@@ -67,7 +64,11 @@ namespace Avalonia.Markup.Xaml
using (var stream = asset.stream)
{
var absoluteUri = uri.IsAbsoluteUri ? uri : new Uri(baseUri, uri);
- return runtimeLoader.Load(stream, asset.assembly, null, absoluteUri, false);
+ return runtimeLoader.Load(stream, new RuntimeXamlLoaderConfiguration
+ {
+ LocalAssembly = asset.assembly,
+ BaseUri = absoluteUri
+ });
}
}
diff --git a/src/Markup/Avalonia.Markup.Xaml/RuntimeXamlLoaderConfiguration.cs b/src/Markup/Avalonia.Markup.Xaml/RuntimeXamlLoaderConfiguration.cs
new file mode 100644
index 0000000000..9caf94fba6
--- /dev/null
+++ b/src/Markup/Avalonia.Markup.Xaml/RuntimeXamlLoaderConfiguration.cs
@@ -0,0 +1,36 @@
+using System;
+using System.Reflection;
+
+namespace Avalonia.Markup.Xaml;
+
+#nullable enable
+
+public class RuntimeXamlLoaderConfiguration
+{
+ ///
+ /// The URI of the XAML being loaded.
+ ///
+ public Uri? BaseUri { get; set; }
+
+ ///
+ /// Default assembly for clr-namespace:.
+ ///
+ public Assembly? LocalAssembly { get; set; }
+
+ ///
+ /// The optional instance into which the XAML should be loaded.
+ ///
+ public object? RootInstance { get; set; }
+
+ ///
+ /// Defines is CompiledBinding should be used by default.
+ /// Default is 'false'.
+ ///
+ public bool UseCompiledBindingsByDefault { get; set; } = false;
+
+ ///
+ /// Indicates whether the XAML is being loaded in design mode.
+ /// Default is 'false'.
+ ///
+ public bool DesignMode { get; set; } = false;
+}
diff --git a/src/tools/Avalonia.Designer.HostApp/DesignXamlLoader.cs b/src/tools/Avalonia.Designer.HostApp/DesignXamlLoader.cs
index 7af29a56a1..7009151998 100644
--- a/src/tools/Avalonia.Designer.HostApp/DesignXamlLoader.cs
+++ b/src/tools/Avalonia.Designer.HostApp/DesignXamlLoader.cs
@@ -8,9 +8,11 @@ namespace Avalonia.Designer.HostApp
{
class DesignXamlLoader : AvaloniaXamlLoader.IRuntimeXamlLoader
{
- public object Load(Stream stream, Assembly localAsm, object o, Uri baseUri, bool designMode)
+ public object Load(Stream stream, RuntimeXamlLoaderConfiguration configuration)
{
- return AvaloniaXamlIlRuntimeCompiler.Load(stream, localAsm, o, baseUri, designMode);
+ return AvaloniaXamlIlRuntimeCompiler.Load(stream,
+ configuration.LocalAssembly, configuration.RootInstance, configuration.BaseUri,
+ configuration.DesignMode, configuration.UseCompiledBindingsByDefault);
}
}
}
diff --git a/tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/CompiledBindingExtensionTests.cs b/tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/CompiledBindingExtensionTests.cs
index a09abdecce..77067fa517 100644
--- a/tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/CompiledBindingExtensionTests.cs
+++ b/tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/CompiledBindingExtensionTests.cs
@@ -1603,6 +1603,27 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
}
}
+ [Fact]
+ public void Uses_RuntimeLoader_Configuration_To_Enabled_Compiled()
+ {
+ using (UnitTestApplication.Start(TestServices.StyledWindow))
+ {
+ var xaml = @"
+";
+ var control = (AssignBindingControl)AvaloniaRuntimeXamlLoader.Load(xaml, new RuntimeXamlLoaderConfiguration
+ {
+ UseCompiledBindingsByDefault = true
+ });
+ var compiledPath = ((CompiledBindingExtension)control.X).Path;
+
+ var node = Assert.IsType(Assert.Single(compiledPath.Elements));
+ Assert.Equal(typeof(string), node.Property.PropertyType);
+ }
+ }
+
void Throws(string type, Action cb)
{
try
diff --git a/tests/Avalonia.Markup.Xaml.UnitTests/XamlTestBase.cs b/tests/Avalonia.Markup.Xaml.UnitTests/XamlTestBase.cs
index 2bc82d1353..2fc4867b35 100644
--- a/tests/Avalonia.Markup.Xaml.UnitTests/XamlTestBase.cs
+++ b/tests/Avalonia.Markup.Xaml.UnitTests/XamlTestBase.cs
@@ -20,8 +20,8 @@ namespace Avalonia.Markup.Xaml.UnitTests
class TestXamlLoaderShim : AvaloniaXamlLoader.IRuntimeXamlLoader
{
- public object Load(Stream stream, Assembly localAsm, object o, Uri baseUri, bool designMode)
- => AvaloniaRuntimeXamlLoader.Load(stream, localAsm, o, baseUri, designMode);
+ public object Load(Stream stream, RuntimeXamlLoaderConfiguration configuration)
+ => AvaloniaRuntimeXamlLoader.Load(stream, configuration);
}
}
}