Skizzor is a configurable XAML→Razor transpiler, shipped as a NuGet package family. At its center sits a source- and target-neutral abstract UI tree (IR). Around it are swappable parsers (source side) and mappers (target side) — so any XAML dialect can be combined with any Razor component library, without the parser and mapper knowing about each other.
flowchart LR
A["<b>Avalonia</b><br/>(XAML)<br/><br/>Skizzor.Avalonia<br/><i>IXamlParser</i>"]
S["<b>Skizzor</b><br/>abstract UI tree<br/>Parser · Mapper · Emit<br/><br/>Skizzor.Core"]
B["<b>Blazor</b><br/>(Razor)<br/><br/>Skizzor.Radzen<br/><i>IComponentMapper</i>"]
A -->|parse| S -->|emit| B
The data flow is a three-stage pipeline:
XAML ──▶ IXamlParser ──▶ [UI tree] ──▶ IComponentMapper ──▶ [UI tree] ──▶ RazorEmitter ──▶ Razor
(source vocabulary) (target vocabulary, (target-neutral)
emit-ready)
- Parsers read a XAML dialect and populate the UI tree with source vocabulary
(
Button,{Binding}). - Mappers rewrite the tree into target vocabulary (
Button→RadzenButton) and lower source-specific values (bindings, resources, markup extensions) into emit-ready literals and expressions. - The emitter renders any emit-ready tree to Razor and lives in
Core, because rendering is target-independent.
| Package | Role | Status |
|---|---|---|
Skizzor.Core |
IR (abstract UI tree), parser/mapper/emitter abstractions, pipeline, default emitter, diagnostics | ✅ |
Skizzor.Avalonia |
Parser for Avalonia XAML (AXAML), IXamlParser |
✅ |
Skizzor.Radzen |
Mapper onto Radzen Blazor components, IComponentMapper |
✅ |
Skizzor.Wpf |
Parser for WPF XAML | planned |
Skizzor.MudBlazor |
Mapper onto MudBlazor components | planned |
using Skizzor.Avalonia;
using Skizzor.Core.Pipeline;
using Skizzor.Radzen;
var pipeline = new TranspilerPipeline(new AvaloniaXamlParser(), new RadzenMapper());
var result = pipeline.Transpile(axaml);
if (result.Succeeded)
{
Console.WriteLine(result.Code);
}
foreach (var diagnostic in result.Diagnostics)
{
Console.WriteLine(diagnostic);
}Example — from this AXAML …
<StackPanel Orientation="Vertical">
<TextBlock Text="{Binding Title}" />
<TextBox Text="{Binding Name, Mode=TwoWay}" />
<Button Content="Save" Click="OnSave" IsEnabled="{Binding CanSave}" />
</StackPanel>… Skizzor produces this Razor:
<RadzenStack Orientation="Vertical">
<RadzenText Text="@(Title)" />
<RadzenTextBox @bind-Value="Name" />
<RadzenButton Text="Save" Click="@(OnSave)" IsEnabled="@(CanSave)" />
</RadzenStack>The RadzenMapper is driven by a ComponentMap. The default set can be extended
or overridden:
var map = RadzenMapper.CreateDefaultMap();
map.Map("Expander", "RadzenPanel")
.MapAttribute("Header", "Text");
var mapper = new RadzenMapper(map);dotnet buildAll packages target netstandard2.0 (maximum consumability, including from Roslyn
source generators).
MIT — see LICENSE.