A XAML file reaches a running program in one of two ways: it is compiled into the program by the build, or it is loaded from text at run time. Most applications compile their pages and windows and load only files that users or tools supply.
Markup compilation (WPF)
- The build action
Page(orApplicationDefinitionfor the application) sends the file to the markup compiler, which reads it with System.Xaml. - It writes the generated class: a partial class named by
x:Class(MainWindow.g.cs), withInitializeComponent(), a field for eachx:Nameelement, and the connection of events to the handlers named in the markup.InitializeComponentloads the compiled markup throughApplication.LoadComponentwith apack://address of the BAML resource, then callsConnectfor each connection. - It writes the BAML file (
MainWindow.baml) and embeds it in the assembly’s resources, namedmainwindow.bamlinsideAssemblyName.g.resources. - The developer’s half of the class, the code-behind (
MainWindow.xaml.cs), is another part of the same class; its constructor callsInitializeComponent()and it defines the handlers.
The generated and the written halves are checked together by the language compiler: a handler named in markup that the class does not define, or an x:Name that clashes with a member, is a compile error in C#, not a XAML error. UWP, WinUI, MAUI and Avalonia generate a partial class with InitializeComponent as well, but differ in what is compiled: UWP and WinUI compile to a binary form (.xbf, XAML Binary Format) with generated bindings for x:Bind; MAUI can compile to code (source generation) or load the XAML when the page is made; Avalonia can compile its XAML into code and, with AvaloniaResource items, load from embedded resources.
Loose XAML
A file that is not compiled is read at run time by XamlReader.Load(stream) or XamlServices.Load in WPF, XamlReader.Load(string) in UWP and WinUI, LoadFromXaml in MAUI, AvaloniaRuntimeXamlLoader in Avalonia. A loose file cannot use x:Class, event handlers or x:Code (there is no compiled class to connect them to), and may use XAML 2009 features in WPF. It is how an application loads skins, templates and saved documents (XamlWriter.Save writes an object tree as XAML, with limits). Loading arbitrary XAML runs constructors and sets properties of any type the namespaces reach, so loose XAML from an untrusted source is a security risk and frameworks restrict which types it may create.
BAML
BAML (Binary Application Markup Language, .baml) is the compiled form of a WPF XAML file: the same tree as a stream of records, with strings, type names and property names replaced by numbered table entries so that loading needs no XML parsing and no type lookup by name. A .baml file starts with a header: the length 12 as a 32-bit number, the 12 bytes of the UTF-16 string MSBAML, and three 4-byte version numbers (reader, updater, writer; the two files on this Mac, a Debug and a Release build of one WPF window, hold the same value, 0x0060, in all three). Then comes a sequence of records, each starting with a one-byte type that tells the record (document start and end, element start and end, property, property with converter, property with extension, text, namespace declaration, type, attribute and string-table information, line and position information, and so on). Decompilers such as ILSpy and the BAML reader of the Avalonia and WPF source read it back into XAML. Markup compiled to BAML supports XAML 2006 only: the 2009 features are not in the format.
The viewer does not read .baml files: a BAML file is binary and appears here only as bytes. The record layout is not described on this site; see Not described.
What the compiler checks and what it does not
- Checked at build: that the XML is well formed; that every type and property named exists (with the project’s references); that attribute values convert; that
x:Namevalues are unique in their scope and valid identifiers; thatx:Classis on the root only; that event handlers exist with the right signature (by the language compiler); thatx:Keyis not repeated in one dictionary (WPF raises that at load time for dictionaries it does not compile). - Checked at load: that
StaticResourcekeys exist; that a name used by a binding or animation exists in the scope; that the data context has the property a binding names (a failed binding is logged, not thrown).
The viewer checks what it can from the file alone (the first list, minus the types and the handlers) and says so on the overview page.
Not described
Known, not yet covered
- Reference: the BAML record layout (the numeric codes of the record types, the layout of each record, the attribute and string tables, the extension and converter records) is not described. The source of WPF (the
BamlReaderandBamlRecordsindotnet/wpf) and ILSpy define it, and they were not read in full here. - Reference: the XAML Binary Format (
.xbf) of UWP and WinUI is named; its layout is not documented publicly and is not described.
Unknown
- Reference: the two
.bamlfiles on this Mac were checked only for their header (the bytes after it, which hold the type names of the window, were seen but not decoded); the record type list above is from knowledge of the format, not from decoding those files.