AXSG can preserve common legacy Avalonia code-behind patterns by rewriting compiled AvaloniaXamlLoader.Load(...) calls to AXSG-generated initializer helpers during the build.
This is a migration bridge. It does not remove AvaloniaXamlLoader from Avalonia or change Avalonia's NuGet package surface. It changes your compiled application assembly so supported call sites end up on AXSG's generated object-graph path.
Many Avalonia projects still contain class-backed code such as:
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}
or:
public ServiceProviderPanel(IServiceProvider serviceProvider)
{
AvaloniaXamlLoader.Load(serviceProvider, this);
}
Before AXSG IL weaving, those call sites had to be removed or manually guarded during migration because they bypassed AXSG's generated InitializeComponent(bool loadXaml = true) path.
With IL weaving enabled, AXSG can keep those common source shapes working while still routing the compiled app through generated AXSG initialization.
AXSG runs the weaving pass only when all of these are true:
XamlSourceGenIlWeavingEnabled is trueThe pass runs after CoreCompile and before output-copy targets, so the rewritten assembly is what the app and tests execute.
AXSG rewrites these legacy call patterns when the target object is the current instance:
AvaloniaXamlLoader.Load(this);AvaloniaXamlLoader.Load(serviceProvider, this);The source spelling does not matter. Imported and fully-qualified forms both compile to the same IL call shape, so both are supported.
AXSG does not rewrite every possible AvaloniaXamlLoader call. The current pass is intentionally narrow and deterministic.
These shapes are left alone:
AvaloniaXamlLoader.Load(otherInstance);var self = this; AvaloniaXamlLoader.Load(self);The current rule is direct same-instance migration support, not arbitrary object-loader interception.
For class-backed AXSG documents, the emitter now generates stable helper overloads:
__InitializeXamlSourceGenComponent(self)__InitializeXamlSourceGenComponent(serviceProvider, self)The weaver redirects supported AvaloniaXamlLoader.Load(...) calls to those helpers.
That means rewritten calls go through the same generated initialization body that powers AXSG class-backed XAML:
The weaving pass is therefore compatibility glue, not a second runtime path.
Once a project is fully migrated, the cleanest shape is still:
public MainWindow()
{
InitializeComponent();
}
with no hand-written AvaloniaXamlLoader wrapper at all.
If you want to switch to AXSG without editing all existing code-behind immediately, keep the legacy wrapper temporarily and let AXSG rewrite it:
public MainWindow()
{
InitializeComponent();
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}
This also applies to App.axaml.cs.
If you want the build to enforce source cleanup instead of silently bridging it, disable weaving:
<PropertyGroup>
<XamlSourceGenIlWeavingEnabled>false</XamlSourceGenIlWeavingEnabled>
</PropertyGroup>
With weaving disabled, the older AXSG rule comes back: a hand-written parameterless InitializeComponent() wrapper can intercept the constructor call and bypass the generated AXSG initializer.
These switches are MSBuild-only build-integration properties. They do not map to xaml-sourcegen.config.json.
| Property | Default | Meaning |
|---|---|---|
XamlSourceGenIlWeavingEnabled |
true |
Canonical switch for the post-compile rewrite pass. |
AvaloniaSourceGenIlWeavingEnabled |
mirrors XamlSourceGenIlWeavingEnabled |
Compatibility alias for existing Avalonia-prefixed configuration. |
XamlSourceGenIlWeavingStrict |
true |
Fails the build when AXSG matches a supported loader call on a source-generated type but cannot find the generated initializer helper to rewrite to. |
AvaloniaSourceGenIlWeavingStrict |
mirrors XamlSourceGenIlWeavingStrict |
Compatibility alias. |
XamlSourceGenIlWeavingVerbose |
false |
Prints inspection, match, and rewrite counts for the pass. |
AvaloniaSourceGenIlWeavingVerbose |
mirrors XamlSourceGenIlWeavingVerbose |
Compatibility alias. |
XamlSourceGenIlWeavingBackend |
Metadata |
Selects the scan backend for the weaving pass. Metadata uses System.Reflection.Metadata; Cecil keeps the legacy Mono.Cecil scan path. |
AvaloniaSourceGenIlWeavingBackend |
mirrors XamlSourceGenIlWeavingBackend |
Compatibility alias. |
Example:
<PropertyGroup>
<AvaloniaXamlCompilerBackend>SourceGen</AvaloniaXamlCompilerBackend>
<XamlSourceGenIlWeavingEnabled>true</XamlSourceGenIlWeavingEnabled>
<XamlSourceGenIlWeavingVerbose>true</XamlSourceGenIlWeavingVerbose>
<XamlSourceGenIlWeavingBackend>Metadata</XamlSourceGenIlWeavingBackend>
</PropertyGroup>
When the pass rewrites anything, AXSG logs a build message like:
[AXSG.Build] IL weaving inspected 11 type(s), matched 3 AvaloniaXamlLoader call(s), and rewrote 3 call(s) in '.../SourceGenIlWeavingSample.dll'.
Use XamlSourceGenIlWeavingVerbose=true when you want that message even for zero-rewrite builds.
If strict mode is enabled and AXSG finds a supported loader call on a source-generated type but cannot find the generated initializer helper, the build fails. That usually indicates one of these problems:
If the app still behaves like classic Avalonia loading, check:
AvaloniaXamlCompilerBackend=SourceGenXamlSourceGenIlWeavingEnabled=trueRewritten call sites land on the same generated AXSG initializer helpers used by the normal class-backed path, so hot reload and hot design registration stay intact.
The sample app at samples/SourceGenIlWeavingSample covers:
App initialization through AvaloniaXamlLoader.Load(this)AvaloniaXamlLoader.Load(this)AvaloniaXamlLoader.Load(serviceProvider, this)The corresponding runtime tests verify that rewritten calls still register tracked documents for hot reload.
AXSG IL weaving does not:
AvaloniaXamlLoader from the Avalonia packageInitializeComponent() directlyIt is a build-time migration aid for supported legacy patterns.