Rob Relyea

xaml:Blog

January 2004 - Posts

  • MarkupCompilation: XAML, BAML, .g.cs Details

    Filed under: , ,

    WinFX allows you use XAML to declaratively define your UI, interactive media, or document.  XAML is a great way to define these things.  However, XAML isn't what we'd prefer to use at runtime.

     

    With HTML, parsing of the .html file is done at runtime.  This leads to the following problems:

    1) the runtime spends a lot of energy to convert markup into objects

    2) often errors are caught by the user, not the developer/author

     

    Avalon allows runtime parsing of XAML, however we think you'll see the benefits of compiling most of your markup.

     

    XAML Naming History

    XAML originally meant "eXtensible Avalon Markup Language".  Before one of our first design previews we didn't think the "Avalon" code name would be public at all, so it morphed into "eXtensible Application Markup Language".  (To my surprise, we still did use the “Avalon” name.)  We eventually learned that we had a technology that wouldn't only work with Avalon, but would be more generally useful as well, confirming that name change was a good one.  What we will end up calling it, I don't know.  Whatever we call it, I want it to be a nice pronouncable acronym.  We pronounce XAML like "zammel".  (See Kevin Dente's funny post.)

     

    Markup Compilation Details

    During the build of a Longhorn application, before we let the appropriate language compiler (C#, VB, C++, etc...) compile the appropriate code, we compile the markup.

     

    Given a sample file (foo.xaml):

    <DockPanel xmlns="http://schemas.microsoft.com/xaml/2003"

        xmlns:def="Definition" def:Class="MyNS.MyClass">

        <Button ID="b1" Click="foo">click here</Button>

        <TextBox ID="tb1" />

    </DockPanel>

     

    When foo.xaml is compiled, the following happens:

    1) Our markup compiler parses foo.xaml (using our parser - which uses System.Xml.XmlTextReader)

    2) Our markup compiler calls a BAMLWriter to create foo.baml in obj\release\.  (more details on what is in the BAML file later...)

    3) Our markup compiler creates a CodeDom representation of a new partial class (more details on what that class does later...) and we ask the code to be saved into foo.g.cs in obj\release\. (if your language of choice is C#.)

     

    Foo.baml - What is it?

    The B in BAML stands for Binary, because BAML is not meant for human reading or writing.  You may ask why call something "Binary Application Markup Language" - aren't Binary and Markup contradictory.  BAML is a binary representation of the object hierarchy and properties defined in the source XAML file.  It has been pre-tokenize, so at runtime, loading of a BAML file should be much faster than loading a XAML file.

     

    Foo.g.cs - What is it?

    The .g stands for "Generated".  Before we get into more detail about this file, you need to understand that every XAML file is actually defining a new class.  In the foo.xaml example from above, the XAML file is declaring that it is building a new class like this:

     

    namespace MyNS

    {

        class MyClass : DockPanel

        {

        }

    }

     

    In fact, that is the beginning of the code put into foo.g.cs.  We also

    add the "partial" keyword:

        partial class MyClass : DockPanel

    The partial keyword in C# (and a related Extends keyword in VB) means that this class is also defined elsewhere, generally in another code file.  We use this so that foo.xaml.cs (the code-beside file) can define the other part of the same class.

     

    MyClass in .g.cs defines:

    A field for every element with an ID attribute.

        public Button b1;

        public TextBox tb1;

    A constructor that creates the tree of objects by calling LoadBaml("foo.baml").

    A routine which gets called back whenever an element is created with an ID.  The field b1 will get set to the value of the Button that was created for it at that time.  Event hookup also happens in this routine.

     

    CAML vs BAML

    At one point we thought we would have 2 different settings for markup compilation: Optimization="Speed" and Optimization="Download".  In a future milestone, we'll be removing Optimization="Speed" or what some people internally call CAML - for for Compiled.  Optimized for download maps to generating .baml & .g.cs as described above.  Optimized for speed only generates .g.cs file and does all tree creation in code in that file.

     

    BAML Only!

    We think we are going to cut CAML because:

    1) BAML is just as fast as CAML today and can probably be made faster.

    2) Having one code path is better than two.  In the PDC bits (that everybody is using now) we had spotty quality in the 2 different code paths.  Some features only worked with one or the other.  We'll be able to optimize, security threat analyze, and test BAML much better than we could have done with CAML and BAML.

    3) Localization in an optimal way is easier with BAML.  You don't want localizable strings embedded in your .exe, but instead, you want those to be stored in a sattelite assembly.  (Perhaps this will be a future topic.)

    4) Download size is smaller with an embedded BAML vs compiled IL into the Exe.

    5) Incremental rendering is possible with BAML.  HTML allows you to see parts of a document before the entire document is downloaded.  BAML has the same capability.  CAML doesn't - you need to download the entire definition of a class and the assembly it is in before you can instantiate the first element of a page.

    6) I'll modify this list if I remember more reasons...

     

    Where does the BAML go?

    By default, we put all items of Type="Resources" into .net resources and embed them in an assembly.  You can play with project file settings in msbuild to individually control each file if you like.  When somebody drills into localization, we'll cover the details of that.

     

    In Summary:

    Our compilation model allows people to get the benefit of XML during authoring/development time, without having to pay for it at runtime.

     

     

    Hey, I'm Posting Again

    Ok, well I'm back after my first blog "pause".  I went to Japan to do some Avalon talks in mid-December (my 49 hours in Tokyo- did 3 talks, slept a total of 7 hours in 2 nights there, i'm glad i did it, but next time I want to spend more time there...).  When I returned to the airport in Seattle my family met me there and we flew to the East Coast for a friend's wedding.  I worked about half-time during the holidays.  Since the new year, I've been cranking on:

    • XAML2004 design
    • avalon api review (almost done with a pmvt walk through of MSAvalon.Windows in PF.dll, PC.dll and WB.dll)
    • improving xaml.xsd
    • VS integration issues
    • interviewing several PM candidates for our team
    • a spec for allowing you to invent your own xmlns uri for use in xaml
    • and a few more things.

      It has been a great month - a great start to the year.

    PostTypeIcon
    43,138 Views