Goal
.axaml files into IL, resources, and runtime objects.Why this matters
Prerequisites
When you add .axaml files, the SDK-driven build uses two MSBuild tasks from Avalonia.Build.Tasks:
GenerateAvaloniaResources (external/Avalonia/src/Avalonia.Build.Tasks/GenerateAvaloniaResourcesTask.cs)
AvaloniaResource item into the *.axaml resource bundle (avares://).XamlFileInfo.Parse, records x:Class entries, and writes /!AvaloniaResourceXamlInfo metadata so runtime lookups can map CLR types to resource URIs.BuildEngine.LogError) if it sees invalid XML or duplicate x:Class declarations.CompileAvaloniaXaml (external/Avalonia/src/Avalonia.Build.Tasks/CompileAvaloniaXamlTask.cs)
XamlCompilerTaskExecutor.Compile, which runs the XamlIl compiler over each XAML resource, generates partial classes, compiled bindings, and lookup stubs under the CompiledAvaloniaXaml namespace, then rewrites the IL in-place.$(IntermediateOutputPath).Key metadata:
AvaloniaResource item group entries exist by default in SDK templates; make sure custom build steps preserve the AvaloniaCompileOutput metadata so incremental builds work.<VerifyXamlIl>true</VerifyXamlIl> to enable IL verification after compilation; this slows builds slightly but catches invalid IL earlier.<AvaloniaUseCompiledBindingsByDefault>true</AvaloniaUseCompiledBindingsByDefault> opts every binding into compiled bindings unless opted out per markup (see Chapter 08).XamlIl is Avalonia's LLVM-style pipeline built on XamlX:
XamlX.Parsers) transforms XAML into an AST (XamlDocument).Avalonia.Markup.Xaml.XamlIl.CompilerExtensions) rewrite the tree, resolve namespaces (XmlnsDefinitionAttribute), expand markup extensions, and inline templates.XamlCompilerTaskExecutor) creates classes such as CompiledAvaloniaXaml.!XamlLoader, CompiledAvaloniaXaml.!AvaloniaResources, and compiled binding factories.external/Avalonia/src/Markup/Avalonia.Markup.Xaml/XamlIl/Runtime/XamlIlRuntimeHelpers.cs) provide services for deferred templates, parent stacks, and resource resolution at runtime.Every .axaml file with x:Class="Namespace.View" yields:
AvaloniaXamlIlRuntimeXamlLoader. This ensures your code-behind InitializeComponent() wires the compiled tree.AvaloniaXamlLoader.Load(new Uri("avares://...")) can find the compiled loader.If you set <SkipXamlCompilation>true</SkipXamlCompilation>, the compiler bypasses IL generation; AvaloniaXamlLoader then falls back to runtime parsing for each load (slower and reflection-heavy, but useful during prototyping).
AvaloniaXamlLoader (external/Avalonia/src/Markup/Avalonia.Markup.Xaml/AvaloniaXamlLoader.cs) chooses between:
CompiledAvaloniaXaml.!XamlLoader.TryLoad(string) in the owning assembly and instantiates the pre-generated tree.AvaloniaLocator.CurrentMutable.Register<IRuntimeXamlLoader>(...). This constructs a RuntimeXamlLoaderDocument with your stream or string, applies RuntimeXamlLoaderConfiguration, and parses with PortableXaml + XamlIl runtime.Runtime configuration knobs:
UseCompiledBindingsByDefault toggles compiled binding behaviour when parsing at runtime.DiagnosticHandler lets you downgrade/upgrade runtime warnings or feed them into telemetry.DesignMode ensures design-time services (Design.IsDesignMode, previews) do not execute app logic.Use cases for runtime loading:
IRuntimeXamlLoader).Avalonia uses XmlnsDefinitionAttribute (external/Avalonia/src/Avalonia.Base/Metadata/XmlnsDefinitionAttribute.cs) to map XML namespaces to CLR namespaces. Assemblies such as Avalonia.Markup.Xaml declare:
[assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Markup.Xaml.MarkupExtensions")]
Guidelines:
[assembly: XmlnsDefinition] for component libraries so users can xmlns:controls="clr-namespace:MyApp.Controls" or reuse the default Avalonia URI.[assembly: XmlnsPrefix] (also in Avalonia.Metadata) to suggest a prefix for tooling.IXamlTypeResolver is available through the service provider (Extensions.ResolveType). When you write custom markup extensions, you can resolve types that respect XmlnsDefinition mappings.
All markup extensions inherit from Avalonia.Markup.Xaml.MarkupExtension (MarkupExtension.cs) and implement ProvideValue(IServiceProvider serviceProvider).
Avalonia supplies extensions such as StaticResourceExtension, DynamicResourceExtension, CompiledBindingExtension, and OnPlatformExtension (external/Avalonia/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/*). The service provider gives access to:
INameScope for named elements.IAvaloniaXamlIlParentStackProvider for parent stacks (Extensions.GetParents<T>()).IRootObjectProvider, IUriContext, and design-time services.Custom markup extension example:
public class UppercaseExtension : MarkupExtension
{
public string? Text { get; set; }
public override object ProvideValue(IServiceProvider serviceProvider)
{
var source = Text ?? serviceProvider.GetDefaultAnchor() as TextBlock;
return source switch
{
string s => s.ToUpperInvariant(),
TextBlock block => block.Text?.ToUpperInvariant() ?? string.Empty,
_ => string.Empty
};
}
}
Usage in XAML:
<TextBlock Text="{local:Uppercase Text=hello}"/>
Tips:
Text; the extension may be instantiated at parse time without parameters.serviceProvider.GetService<IServiceProvider>) sparingly; they run on every instantiation.IProvideValueTarget or use XamlIlRuntimeHelpers.DeferredTransformationFactoryV2.XamlIl optimises templates and bindings when you:
x:Class so partial classes can inject compiled fields (InitializeComponent).x:DataType on DataTemplates to enable compiled bindings with compile-time type checking.x:CompileBindings="False" on a scope if you need fallback to classic binding for dynamic paths.The compiler hoists resource dictionaries and template bodies into factory methods, reducing runtime allocations. When you inspect generated IL (use ilspy), you'll see new Func<IServiceProvider, object>(...) wrappers for control templates referencing XamlIlRuntimeHelpers.DeferredTransformationFactoryV2.
AvaloniaXamlDiagnosticCodes include the original file path; MSBuild surfaces them in IDEs with line/column.XamlLoadException (XamlLoadException.cs) indicates missing compiled loaders or invalid markup; the message suggests ensuring x:Class and AvaloniaResource build actions.<AvaloniaXamlIlVerboseOutput>true</AvaloniaXamlIlVerboseOutput> to print stack traces from the XamlIl pipeline.avalonia-preview (design-time host) to spot issues with namespace resolution; the previewer logs originate from the runtime loader and respect RuntimeXamlLoaderConfiguration.DiagnosticHandler.<UseCompiledBindingsByDefault> and <VerifyXamlIl> match your requirements.[assembly: XmlnsDefinition] for every exported namespace; document the suggested prefix..axaml under the project root or set Link metadata so GenerateAvaloniaResources records the intended resource URI.AvaloniaHeadless (Chapter 21) to exercise runtime loader paths without the full compositor.dotnet build /bl. Open the MSBuild log and confirm GenerateAvaloniaResources and CompileAvaloniaXaml run with the expected inputs.[assembly: XmlnsDefinition("https://schemas.myapp.com/ui", "MyApp.Controls")], and consume it from a separate app.{local:Uppercase} as above, inject IServiceProvider utilities, and write tests that call ProvideValue with a fake service provider.<AvaloniaUseCompiledBindingsByDefault>false>, then selectively enable compiled bindings in XAML with {x:CompileBindings} and observe the generated IL (via dotnet-monitor or ILSpy).IRuntimeXamlLoader in a test harness to load XAML from strings, flip UseCompiledBindingsByDefault, and log diagnostics through RuntimeXamlLoaderConfiguration.DiagnosticHandler..axaml file still has x:Class and InitializeComponent is called. Without it, the compiled loader never runs.x:Class errors: two XAML files declare the same CLR type; rename one or adjust the namespace. The compiler stops on duplicates to avoid ambiguous partial classes.XamlTypeResolutionException: ensure the target assembly references the library exposing the type and that you provided an XmlnsDefinition mapping.avares:// fails): verify AvaloniaResource items exist and the resource path matches the URI (case-sensitive on Linux/macOS).obj/*.dll to .gitignore and avoid checking in intermediate outputs.external/Avalonia/src/Avalonia.Build.Tasks/GenerateAvaloniaResourcesTask.csexternal/Avalonia/src/Avalonia.Build.Tasks/CompileAvaloniaXamlTask.cs, external/Avalonia/src/Avalonia.Build.Tasks/XamlCompilerTaskExecutor.csexternal/Avalonia/src/Markup/Avalonia.Markup.Xaml/AvaloniaXamlLoader.cs, RuntimeXamlLoaderDocument.csexternal/Avalonia/src/Markup/Avalonia.Markup.Xaml/XamlIl/Runtime/XamlIlRuntimeHelpers.csexternal/Avalonia/src/Markup/Avalonia.Markup.Xaml/Extensions.cs.axaml files, and what metadata do they emit?[XmlnsDefinition] attributes when publishing a control library?What's next