The Mists of Avalon

This article introduces "Avalon," the exciting new presentation layer of the upcoming Windows version (codenamed Longhorn). I'll first point out what's so fundamentally new and advantageous about the way Avalon deals with graphics, and then show you how to use XAMLPad, a tool that comes with the WinFXTM SDK, to get a first taste of Avalon programming.

In the following parts of this article series, you will see how to use Avalon with .NET code in Visual Studio 2005, and also take a look at the more advanced features of Avalon, such as 3D graphics, animation, and speech.

Many think of Avalon as a future technology and part of Longhorn (which is correct), and hence not yet available (which is wrong): The Beta 1 preview is available to the general public for download (the latest version is of May 2005), and by installing the latest WinFXTM SDK, Avalon applications can be developed with the Visual Studio 2005 Beta 2, which is freely available as well. In fact, many software vendors and individual developers are already busy creating Avalon applications on the current Beta platforms, so they are ready when Longhorn is released.

Note: This article is based on pre-release information from the current WinFXTM SDK Beta, so details might still change. This article will be updated as the WinFXTM SDK gets stable and more details are available.

The Old World: Same Procedure as Every Year...

If you have been developing Win32 applications in C or C++ so far, you will most probably be familiar with the GDI (Graphics Device Interface)—Microsoft Windows' API for device-independent graphics output since 1985. Ever since, the GDI was based on the metaphor of a virtual canvas (the Device Context, or DC), a set of drawing tools like brushes, pens, fonts, bitmaps, and so forth (known as GDI objects) that you could select into a DC in order to use them with the drawing functions (MoveTo, LineTo, Rectangle, Ellipse, TextOut, and so on). The GDI supports basic coordinate translation and scaling, so you could use logical units (like millimeters, inches, twips, or even your own units) for drawing, and have the GDI map them to physical (or device) units, achieving a fair degree of device independence. Ideally, the same drawing code could be used for output to the screen, a printer, or a plotter.

Other Graphics APIs

Just for the sake of completeness: When talking about Windows graphics APIs, the GDI+ (a modernized, more object-oriented revamp of the GDI), OpenGL (an open, multi-platform standard for high-performance 3D graphics, used mostly in scientific visualization and games) and DirectX (an API for direct access to graphics hardware, among others) should not pass unmentioned—all three are alternative, but, with regard to the GDI, much less used graphics APIs available under Win32.

Procedural Drawing

In any case, drawing with the GDI has always been a procedural (or imperative) activity: You wrote code in your favorite language (most probably C or C++, because Visual Basic doesn't directly support GDI calls) and told the GDI, step by step, what to do to get your GUI to look the way you want. It's somewhat like standing next to an artist and giving her instructions:

"Please pick up the blue pen—no, the thick one."

"Okay, now draw a horizontal line across the canvas, at about one third of the canvas height from the top border—leave a margin of half an inch to the left and right."

"Fine. Now put down the blue pen, and pick up the bright red one."

"With that pen, please draw a circle with a bounding rectangle that starts at 4.57 inches from the left and 3.2 inches from the top, and a radius of 2 inches."

"Okay, now take the yellow brush..."

Sounds tedious? It is, but that's the way procedural drawing works (and if you forgot to put down the blue pen, you were eventually arrested by the GDI resource police for stealing pens, and punished with a system crash...). The good news about procedural drawing is that it is flexible; for example, the instruction in the above example "one third of the canvas height" can be easily expressed as an arithmetic construct in any programming language—and hence, the actual position of the line can be made dependent on the current height of the canvas (your window's client area). This is what a typical WM_PAINT handler in Win32 SDK code could look like (it just draws a horizontal line at one third of the client area's height, leaving a margin of 30 pixels to the left and right, and using a blue, four-pixel-wide pen:

case WM_PAINT:
  {
    PAINTSTRUCT ps;
    HDC hdc = BeginPaint(hWnd, &ps);

    // Get our canvas size:
    RECT rcClient;
    GetClientRect(hWnd, &rcClient);

    // Vertical position is at one-third of the height:
    int lineYPos = (rcClient.bottom - rcClient.top) / 3;
    int margin = 30;

    // Create and select blue pen
    HPEN hBluePen = CreatePen(PS_SOLID, 4, RGB(0, 0, 255));
    HGDIOBJ hOldPen = SelectObject(hdc, hBluePen);
 
    // Draw the line
    MoveToEx(hdc, rcClient.left+margin, lineYPos, NULL);
    LineTo(hdc, rcClient.right-margin, lineYPos);
 
    // Clean up...
    SelectObject(hdc, hOldPen);
    DeleteObject(hBluePen);
    EndPaint( hWnd, &ps );
  }
  break;

What's more, you can use conditional statements (in the case of an error message, use red color for the text; otherwise, black) or loops (you can draw a grid, say, a checker board, by drawing lines or squares in two nested loops, calculating the coordinates from the loop indexes). So, although flexibility is the major advantage of procedural drawing, one of the drawbacks is certainly that it requires you to break down the entire drawing code into fine-grained steps—everything needs to be said explicitly and in great detail.

Now, how would it be if, instead of giving step-by-step instructions, you could simply provide a sketch of the drawing, and have the artist elaborate on that? You could even decide about how detailed the sketch would be—either make the sketch rather... well, sketchy, and let the artist put her creativity into the details of execution, or, on the other end of the spectrum, provide a very detailed sketch and leave little room for interpretation. Like the idea? Then, welcome to the world of declarative graphics programming!

Declaration of Independence

The declarative approach is, to some extent, the exact opposite of the procedural one: Instead of specifying how you want something to be done, you rather specify what you want as a result, and leave it up to the executing instance how exactly it fulfills your request. A familiar example of a declarative description is a Web page that you might design in HTML (HyperText Markup Language): You define the logical structure of your document, including headers, sub headers, paragraphs, tables, emphasized text, and the like, but it is up to the browser on the client side how exactly the page will be rendered. If you like, you can of course get into more detail and also specify font sizes, positions, and exact spacing for table cells—the point is that you can, but need not be so explicit.

In the IT world, we encounter the dualism between the procedural and the declarative paradigm all over the place. For example, a macro in Excel (which typically consists of instruction sequences, like "select a range of cells, copy them, move the cell cursor to another place, paste...") is procedural. An Excel formula, OTOH, is declarative: You just specify that you want the sum of a range of cells, divided by the number of months to appear in the cell where you put the formula, and leave it up to the spreadsheet's calculation engine how, and, more specifically, in which order to perform the calculation steps that lead to the desired result. By the way: The declarative nature of spreadsheet formulas has been one of the major reasons for the enormous success of spreadsheet applications like VisiCalc, Lotus 1-2-3 and later Excel, because they allowed users to create solutions tailored to their needs without having to learn how to program. To non-programmers, it is much more natural to specify what they want instead of explaining step by step how they want it to be done.

Almost all of the more widely used programming languages are imperative—two prominent exceptions being Prolog and LISP, which are both declarative languages.

Note: As with most dualisms, there is no hard dividing line between "procedural" and "declarative;" some approaches are more procedural (they usually rely more on code) whereas others are more declarative (which normally means less code and more data). One of the main advantages of the latter is that it is much easier to build editors and other tools for declarative data—but I'll come back to that in a moment.

Introducing Avalon

Okay, now where and how does Avalon come in? "Avalon" is the codename for the presentation subsystem of WinFX, an extension of the .NET 2.0 Framework, and the new application programming model for the upcoming release of the Windows OS, currently only known as "Longhorn." Longhorn's release to the market is scheduled for mid 2006, and plans are to make WinFX available for Windows XP and Windows Server 2003 as well in early 2006.

For those of you interested in trivia: "Avalon" is the name of a legendary island somewhere in the British Isles. According to the legend, it's the place where King Arthur's body is buried. The title of this article refers to Marion Zimmer Bradley's novel, The Mists of Avalon, which tells the King Arthur myth from a feminist point of view. However, Avalon is also the name of a peninsula in Newfoundland, and that's probably where the name for the Avalon subsystem comes from: Recently, Microsoft tends to use names of geographical locations in the American North-Pacific as codenames for upcoming products and technologies. By the way, "Longhorn" is a saloon in the Whistler-Blackcomb ski resort near Vancouver, and both "Whistler" and "Blackcomb" are codenames as well (for XP and Longhorn Server, respectively). Guess where the Microsoft OS guys hold their design retreats...

Because "Avalon" is a codename, Microsoft puts it in quotation marks in most of its publications. For the sake of simplicity, I will omit the quotation marks for the rest of this article.

The Three Pillars of WinFX

Applications taking advantage of WinFX rest on three subsystems, often referred to as the pillars of WinFX: Avalon (the presentation layer), WinFS (file system and data services), and Indigo (communication services):

Although Avalon and Indigo will be included in the Longhorn Beta 1 announced for summer 2005, WinFS didn't make it and will be added later. This article series focuses on Avalon, the leftmost pillar.

All the capabilities of Avalon are exposed through a managed object model that can be manipulated from any language that supports the CLR (Common Language Runtime). The current Beta 2 of Visual Studio 2005 only allows C# and Visual Basic for creating WinFX applications (so much for a "common" language...)—hopefully, the final release will support C++ as well.

We will soon start to be seeing applications with very fancy and impressive Avalon user interfaces, so it's probably a good idea for developers to get prepared for the new world of UI programming as early as possible (that's precisely why I wrote this article—and probably also the reason why you are reading it).

A major difference between Avalon and the GDI is—you will have guessed it by now—that Avalon uses a declarative model to describe graphic entities of any kind: Windows, Web pages, layout panels, vector graphics, reusable controls, animations, 3D objects, and sceneries.... Everything can be built in a declarative manner.

The Object Tree

Graphics output in an Avalon application is not achieved by a series of sequential instructions, but rather by providing a hierarchy of objects, along with their properties, from the Avalon class model. So, instead of saying "pick up a three-pixel-wide red pen, pick up a yellow, solid brush, draw a circle using the current pen for the border and the current brush to fill it," you would rather say: "We have a window. The window contains a canvas. On the canvas, there is a circle. Ah, and yes, the circle's border is red, and it is filled in yellow. You want to know how thick to draw the border? Three millimeters—unless otherwise specified."

Any graphics scenario in Avalon is constituted by a hierarchy of objects from the Avalon object model: the object tree.

A very simple object tree might be depicted like this:

At the heart of Avalon, there is a compositing, vector-based rendering engine that takes full advantage of the hardware capabilities of the installed graphics adapter (allowing for effects like free scaling, 3D shading, transparency, alpha blending, specular reflection, animation, video, and so forth) to interpret the object tree and render the scenario. However, let's approach it slowly: No 3D, no animation here for the moment: This is what the output might look like when the above object tree is rendered:

In addition to simple geometrical shapes, the Avalon class model includes all sorts of controls like edit boxes, labels, buttons, combo boxes, checkboxes, list controls—everything you now know from MFC or Windows Forms, and much more. However, all those controls are defined as vector graphics—so instead of getting "jagged" when resized, they scale nicely to every possible screen resolution and size. Avalon is mainly vector-based (I say "mainly" because bitmaps and video movies, which are pixel-based, can be integrated as well).

Essentially, the UI of an Avalon application can be built by creating an object tree of GUI elements. In that case, the object tree is often referred to as a UI tree.

A simple UI tree might be depicted like this:

When rendered by the Avalon rendering engine, the output might look similar to the following:

Because all the UI elements are vector-based, the window containing them can be easily resized, and the controls will grow and shrink or rearrange accordingly. Styles can be applied at any level, changing, for example, the font used for all elements, or just the border color of certain buttons.

Even data binding can be added in a declarative manner: You can associate certain controls with data sources like an SQL database or RSS feeds, and when it comes to displaying the controls, the contents will be automatically supplied from those sources—without writing a line of procedural code!

You can create and modify an object tree (or, more specifically, a UI tree) in much the same way you deal with other .NET objects: by using any CLR compliant language (like C++, C# or Visual Basic) to instantiate objects from the .NET class library, setting their properties, and calling their methods. Now, you might wonder where the benefit is, and why all the fuss about declarative drawing? After all, you still need to use a programming language and lastly call procedures to get something displayed.

Hold on—there's more to it. Programmatically creating the UI tree is just one way of doing it (and I will discuss it in an upcoming article). The other is... XAML.

Meet XAML

XAML (pronounced "zammel") is a markup language based on XML that can be used to build an Avalon object tree. XAML is short for eXtensible Application Markup Language. (Surprisingly, the "A" in XAML doesn't stand for "Avalon," but for "Application:" That's because in the future, we won't only be using it for describing Avalon scenarios, but .NET object hierarchies in general. Keep this in mind—one day, you will understand the impact of this statement.)

The following XAML code represents a UI tree and will produce the output shown above:

<Page xmlns="http://schemas.microsoft.com/winfx/avalon/2005"
      Name="Page1">
  <DockPanel Background="Bisque" Name="OuterPanel">

    <StackPanel  Background="LightBlue" DockPanel.Dock="Top"
                 Margin="10,10,10,10">
      <TextBox   HorizontalAlignment="Left"
                 Height="24px"
                 Width="2.6 cm"
                 Margin="20,10,10,10">Text selection</TextBox>

      <Button    HorizontalAlignment="Left" 
                 Height="30px"
                 Width="100px"
                 Margin="20,10,10,10" Name="Button1">Copy</Button>
    </StackPanel>
    
    <Label VerticalAlignment="Top">Select Country:</Label>
    <ComboBox VerticalAlignment="Top"
              Height="24px"
              Width="100px">
              IsSelectionRequired="True">
      <ComboBoxItem>France</ComboBoxItem>
      <ComboBoxItem>Germany</ComboBoxItem>
      <ComboBoxItem>Italy</ComboBoxItem>
      <ComboBoxItem>USA</ComboBoxItem>
    </ComboBox>
  </DockPanel>
</Page>

The XAML tags correspond directly to the objects in the UI tree, with attributes describing their properties, and the tag data representing the textual content of the visual elements. For example, the following Label tag maps to a Label object with the VerticalAlignment attribute set to "Top"and with "Select Country:" as the content, which is the textual representation that the users will see:

<Label VerticalAlignment="Top">Select Country:</Label>

Panels

Panels have no text content of their own: They are rectangular containers for other elements (like text blocks, buttons, controls—and other panels). Panels come in seven flavors, all with their own specific layout properties: BulletPanel, Canvas, DockPanel, Grid, StackPanel, TabPanel, and ToolBarOverflowPanel. Panels can be deeply nested to obtain a very fine-tuned, yet flexible, layout. If that reminds you of tables in HTML, you're only partially right: HTML tables were originally introduced to provide a logical structure for tabular data, arranging it in tables, rows and cells; however, tables have ever been misused by Web page designers for layout purposes, leading to countless problems with the way tables were interpreted and displayed by different browsers. In contrast, Avalon panels have been designed with layout in mind—and by choosing which level of detail you specify as the attributes for panels (like absolute sizes or margins), you can decide to which degree the layout should be fixed or free-flowing depending on the run-time requirements. In short: Avalon panels are meant to do what HTML tables have been long misused for—and much more.

Of course, there are corresponding XAML tags for all the other types of controls from the Avalon class hierarchy: buttons, text boxes, combo boxes, list controls...

Dialog Resources

"But wait," I hear you say, "that way of describing a user interface reminds me of dialog resources in classical Win32 SDK and MFC applications!" And again, you're partially right. Indeed, dialog resource templates have been a strong declarative component in classical Win32 applications (which I've left—purposefully—unmentioned in my introduction about procedural UI design). Instead of writing code for creating a dialog box and adding child controls to it, you could "draw" parts of your UI in a resource editor. At run-time, Windows would create the resulting dialog window with all child controls for you and handle a lot of stuff automatically:

  • Dialog resource templates are designed using "dialog units"—virtual units that are appropriately transformed to device units (pixels) at run-time, depending on the system base font size that the user had selected in the "Display" control panel.
  • The background of dialog windows is painted automatically, again according to system-wide settings the user made.
  • Certain keys (like tab or arrow keys) are automatically handled according to the tab order and geometrical layout specified at design time.

Resources and Localization

Look for a moment at the motivation behind all this: The resource concept has been invented (not by Microsoft, by the way, but by Apple when they first introduced Lisa, the predecessor of the Macintosh, in 1983) to simplify the localization of applications to different countries and languages (now fancily called "cultures" in .NET-speak). An obvious first step is to put any text a user would see not as hard-coded strings into the program's source code, but to keep it in a special data section in a well-defined format so that it could easily be extracted and modified from a compiled executable by using appropriate tools (resource editors or more specialized localization tools); the idea was to be able to translate every textual element of an existing application without having to modify the source code. It soon became obvious that merely translating text strings only did half the job: Text differs significantly in length between various languages. For example, French text is 30% longer in average than the corresponding English text. A button labeled "Open File" would become "Ouvrir fichier" in French; that's 14 characters instead of 9 (a 55% gain!), and chances are good that a button designed to hold the English text would be too short for the French translation. In Italian, it would be "Aprire archivio" (+66%), and Finnish or Hungarian texts are usually even longer. That's why the resource concept was soon extended to entire dialogs and their layout: Now translators, instead of merely translating text, could use tools to adjust the layout of dialogs and the sizes of controls so that the translated text would fit nicely. By the way, similar ideas led to bitmaps and icons ending up in resources as well: Certain pictograms or visual representations of objects (and even colors) can have different meanings in different cultures.

However, the concept of resources ends with menus and dialog boxes: The central parts of the UI of most applications need to be much more flexible than dialog resources allow for, and typically can't be built with a resource editor, but have to be coded procedurally, creating controls and child windows by appropriate API calls, and, as mentioned at the beginning of this article, by drawing significant parts of the UI with procedural GDI calls. Needless to say, that kind of code uses either hard-coded strings and fixed element positions (and hence those applications are impossible to localize with a resource editor), or have to be coded in an extremely flexible way, loading any user-visible text from string table resources, and making the size of procedurally created UI elements depend on the actual text length at run-time. I know, because you are all conscientious developers, you will say "So what; that's the way I've learned it and always done it—of course I keep all my strings in resources!" Heck, of all real-world Windows projects I've seen do far, only about 5% were coded by the textbook. The remaining 95% used hard-coded strings and fixed element positions, making them impossible to localize without modifying the source code.

In other words: A high ridge went through the UI code in classical Win32 applications: On one side, you had the parts designed as resources (declarative!) that were easy to create and localize and had many aspects handled automatically at run-time, and on the other side, the parts that required more fine-tuned control by the developer and hence were coded procedurally—either requiring an enormous extra effort to keep them flexible enough for localization, or completely neglecting that requirement.

But where did I leave off before talking about resources? Ah, Avalon. Its declarative nature makes an important difference in several aspects: Instead of limiting itself to certain trivial and mundane parts of the UI like menus, dialog boxes, and accelerator keys, almost the entire UI of an Avalon application can be designed in a declarative way! This leads to a couple of advantages:

  • Localization: As you have seen, all user-visible text strings in XAML ("zammel", remember, not "ex-ay-em-el") are defined as tag contents. That makes it fairly easy for localization tools to extract and replace those contents by their translated versions. Furthermore, the use of automatic size and layout (buttons that automatically resize to fit their text content, flowing panels, and so on) remove the need to manually change the layout when text lengths change. Avalon's rendering engine will take care of that at run-time. I agree that normally there's no such thing as a free lunch (the TINSTAAFL principle)—but here, you really get the best from two worlds: All the advantages of the easy, but inflexible dialog resource editor layout, combined with automatic resizing and reflowing at run-time—and this time, you don't have to code it yourself; it's already there.

  • Accessibility: Because all textual elements of your UI will be present in a declarative, hierarchically structured form (as data) instead of code, it will be fairly easy to make the contents available to people with disabilities (as an example, think about blind or sight-impaired persons who currently use text-to-speech screen readers or Braille keyboards to get access to Windows applications or Web pages). Although texts in controls are fairly easy to read out, current screen readers use all kind of dirty tricks (like GDI hooks or on-screen OCR) to grab the contents of text drawn into windows on the screen. With GUIs created in Avalon, a consistent and documented interface will be available to access any textual content at run-time. But not only speech output will benefit from the way Avalon stores text content: A very recent addition to WinFX are the speech recognition .NET classes; these provide a managed interface to voice recognition and grammars. They allow for completely speech-enabling an Avalon application by adding a few lines of code to the code-behind file, and without any further coding of your own, users can use voice commands to navigate a form, check options, and enter values into text boxes! You will see in one of the next articles how exactly this can be done.

  • Tools: Here comes one of the major advantages, at least in my opinion, of Avalon's declarative way to store most of what makes a GUI in XAML format: It is very easy to build tools that generate declarative data. That means that you will be able to draw most of your UI—and not just dialog boxes, as it was the case with classical Win32 API programming—with interactive, visual editors. Visual Basic (and now also the Windows Forms elements from .NET 2.0) already go a large step farther into that direction, by allowing you to create a significant part of your UI in a declarative way—most of it, but not all. Although toolbars, status bars, and panes (for free-flowing layout) are already present in the .NET toolbox, today's declarative programming stops when it comes to geometrical shapes, auto-resizing buttons, and complex graphics objects (let alone 3D). With Avalon, all this will be possible.

    You might say: Well, what's so hard about writing a tool that lets me draw a complex graphics scenario and outputs procedural code to draw that? You're right, generating code is not so much a problem—but a true editor can't only be a one-way tool that creates code; it also must be able to reverse the process: Read in existing code and allow you to edit it interactively. And, although this is can be a real challenge with procedural code, it's a piece of cake with XAML (or any other kind of declarative, standardized format, for that matter). Expect not only to see GUI-builder tools, however: Localization tools (as they exist now for resources), tools that convert existing UIs from various formats like resource templates, HTML, 3270 terminal screens, Postscript, and so on to XAML will soon appear on the horizon. Modeling tools for creating complex 3D scenarios with lighting, shading, and animation are already there: For example, ElectricRain's ZAM3D is a very advanced 3D modeling tool that can export its 3D scenarios to XAML—you can download the current beta for evaluation here.

    Update: I read today that Microsoft's Mike Swanson has just written a converter that exports Adobe Illustrator graphics to XAML; it's an Illustrator plug-in, and you can download it from http://www.mikeswanson.com/XAMLExport/. For those who don't know: Illustrator is one of the most important vector-based tools widely used by designers throughout the industry for creating illustrations and logos.

  • Design: This can't be emphasized enough, but it is actually one of the fundamental benefits of Avalon: In classical Win32 UI design, the developer (yes, that's you) already gave away part of the responsibility for the appearance of the UI to translators or localization experts by keeping certain portions of the application in resources, allowing for their modification without access to the source code (and hence without requiring the developer's intervention). In this regard, Avalon goes much farther: Ideally, it puts the entire UI into XAML markup, allowing not only translators, but designers (yep, those guys with the strange haircuts who usually draw the fancy bitmaps you have to load and display in your code via StretchBlt, who tell you which fonts and RGB colors you have to use, and who make the Web pages to sell the product you've been working on so hard) now can, by the use of appropriate tools (no, they don't have to learn XAML) create most of your app's UI.

    (Pause, take a deep breath, preferably from an oxygen mask...)

    Now, if you are a UI guy like me and have always put much of your C++ coding skills and deep GDI knowledge into creating cool user interfaces, this vision will probably scare the hell out of you. But, if you belong to the vast majority of developers I've met so far, you will be more than glad to hear that, finally, designers will take over the job of creating the visual aspects of the GUI (that tricky stuff with colors, fonts, and coordinates, remember?) and let you concentrate on the important aspects of your application—the logic behind the scenes. For the rest of us: Well, they still need someone to develop the tools for the designers...

    Seriously, the advantage of putting the UI design into knowledgeable and skillful hands should be obvious. And still, you don't have to completely give up control: Remember the high ridge I mentioned between resources (declarative) and procedural UI design in classical Win32 programming? Well, Avalon turns this high, solid ridge into a soft, flexible sand dune. You're absolutely free to decide how much of your UI is done in XAML, and how much you do procedurally. You can create UIs with zero lines of C#, you can create UIs with zero lines of XAML, and everything in between. (Although zero lines of both will probably qualify for poor UI design).

To summarize, the real power of XAML in Avalon applications is based on two different levels of abstraction: The first is the abstraction of the business logic (usually written in procedural code-behind) from the visual representation supplied declaratively in XAML (which separates logic from presentation), whereas the second level is the abstraction of the text content from the visual representation, separating design from content and hence allowing for easy localization and data binding.

XAML in .NET Applications

When you create an Avalon application with XAML, one or more files with XAML code will be included in your Visual Studio project, and get compiled to a binary format (BAML) which is added to your assembly as a resource.

An important thing to note is that with XAML code it is not only possible to describe a static scenario (like HTML, Postscript, or GDI Metafiles), but include dynamic effects like animation and even event handling code (more like DHTML or HTML with embedded VBScript or Jscript). If you are familiar with ASP, you will know the idea of code-behind files—actually, a similar concept is normally used with XAML, where the XAML file is compiled to a partial .NET class, and additional .NET code that you can supply will handle the aspects of the GUI which are not described in XAML.

Actually, the comparision to HTML is not so bad: Creating a user interface in XAML is very similar to building a Web page in HTML. However, XAML goes far beyond the capabilities of HTML in that it adds very advanced 2D and 3D vector graphics, storyboard- and timeline-based animation, data binding, event handling and speech recognition and synthesis.

The Mists of Avalon

Installing the Avalon Beta 1 RC Preview

Okay, let's get down to some real stuff now. As mentioned above, everything you need to get started with Avalon is available for free download from Microsoft. You just need to be careful to install the various components in the right order.

Also note that the Avalon Preview requires Windows XP with Service Pack 2, or Windows Server 2003. However, it turned out that the 3D features are not fully supported under Server 2003, so I strongly recommend using XP SP2. If you plan to install the preview on a Virtual PC image, a good idea is to start with a fresh XP SP2 system, and assign at least 512 MB RAM to it.

A word of warning: Because these are Beta components, it is highly recommended that you install them on a separate PC or a Virtual PC image, never on a production system!

Don't Try This at Home...

...and if you do, don't tell anybody about it:

I installed the Avalon runtimes, Visual Studio 2005 Beta 2, and the Avalon Beta1 SDK on a clean XP SP2 Virtual PC image with 512 Mb RAM and used that for a few weeks. Although running on a 2.66 GHz Pentium 4 with 1.25 Gb (real) RAM, everything that involved Avalon was awfully slow—like swimming through mud, if you understand what I mean. I suspect this is partially due to the fact that many of the components involved are still Beta, but mostly because of the way Virtual PC emulates the display hardware. So, I finally decided to ignore all warnings and installed it on my production machine, and saw an enormous performance boost! If you plan to do some serious work with Avalon, it probably outweighs the risk of having to re-install your system later (when you need to uninstall all previews and Betas and install the real thing, for example). Better yet, if you have a dedicated PC with enough CPU power and strong graphics hardware available for installing the Beta.

What You Need

Four things are required before you start Avalon development. I would recommend that you get them all before starting the installation:

  • The current WinFXTM (Avalon and Indigo) Beta1 RC CTP (Community Technology Preview). You can download the latest version (May 2005) here. These are the .NET runtime components required to run applications that make use of any Avalon or Indigo features.
  • A version of Visual Studio 2005 Beta 2. Because the only supported languages for Avalon at this time are C# and Visual Basic, you should have at least one of them. The Express Editions will work fine; you can download them at http://lab.msdn.microsoft.com/express/vcsharp/. Otherwise, you can get one of the full versions at http://lab.msdn.microsoft.com/vs2005/get/. If you are subscribed to MSDN, you can download it directly; if not, you can order a free DVD that will be sent to you by mail.
  • The latest WinFXTM SDK (Software Development Kit)—there's an ISO image available for download on the same page as the CTP. (The link is a little hidden about halfway down the page; if you don't see it, use this link instead). The SDK contains the project templates required to create Avalon applications in Visual Studio, the API documentation (MSDN), and some useful tools (namely XAMLPad, which you will be having a closer look at in a moment).
  • Because the latest SDK is currently only available as an ISO CD image, you need a way to either mount it as a virtual CD-ROM drive, or burn it to a CD. If you decide to use Virtual PC, this is not a problem anyway, because Virtual PC can directly mount an ISO image. If not, either use your favorite burning software to create a CD, or use a third-party tool (for example, WinRAR) that can mount ISO images as virtual CD-ROMs.

The Installation Process

Regardless of whether Visual Studio 2005 Beta 2 is already installed on your system or not, the first step is to install the WinFX runtimes. When you execute the downloaded winfxsetup.exe, it will connect to the Internet and download the actual Avalon and Indigo components, so make sure the machine has Internet access when the installation is running.

After installing the runtime components (you don't need to reboot your system), make sure to install Visual Studio 2005 Beta 2 prior to installing the SDK! This is extremely important because the SDK modifies an existing Visual Studio installation so that you can create Avalon projects with it. So, if Visual Studio 2005 Beta 2 is already installed on your system, fine. If not, go ahead and install it now. Note that, depending on the version you install, this may take some time and also a fair amount of hard disk space (be prepared for about 2 Gb). Important: The WinFX SDK is not compatible with earlier Beta versions of Visual Studio, so make sure that you really have the Beta 2.

Once you have the Visual Studio development environment installed, you can proceed with the installation of the WinFX SDK. Once you have mounted the ISO image (or burned a CD from it and inserted it), start the setup.exe you find in the root directory.

That's it; the hard work is done. Now, you can get to the fun part!

XAMLPad: Interactively Exploring XAML

The WinFX SDK includes XAMLPad, a simple tool that lets you enter XAML markup into a text pane, interprets it on-the-fly, and displays the resulting output in a graphics pane. This is a great platform for playing around with the XAML syntax and getting an immediate, hands-on experience of how the various XAML elements work! After installing the SDK, you should see a program group "Microsoft WinFX SDK" in your Start menu under "All Programs." You find XAMLPad under the "Tools" sub item. When you first launch it, you will see the following:

[img006.jpg]

Note that the root element, in this case a <Grid> element, has already been inserted for you, along with the required ending tag </Grid>. Also, the reference to the XML schema with the URI http://schemas.microsoft.com/winfx/avalon/2005 must be included in the root element of any XAML document.

Avalon and WinFX on MSDN

After installing the WinFX SDK, the local MSDN help integrated with Visual Studio 2005 will also include the WinFX documentation; that means that if you write XAML code using the integrated XML editor of VS 2005 or C# code that uses the new Avalon and Indigo classes, searching, indexing, and IntelliSense support will be available for them as well. You also can use the standalone version of the WinFX beta documentation by opening it directly from the "Microsoft WinFX SDK" item in the "All Programs" of your Start menu. If you want to make sure you always use the most recent version, or just want to skim through the documentation without installing the SDK on your machine, you can always look up the online MSDN version at http://winfx.msdn.microsoft.com/library/ instead.

Hello World

Of course, for us veteran C programmers, the first code sample with any new language or technology always has to be the classical "Hello world!" So, try to enter those famous first words as the content of the Grid element:

[img007.jpg]

Apparently, something went wrong: The text in the XAML panel blushes in shame (or anger?), and you get an error message. Remember what I wrote above about panels? They can't directly contain text content, but act as layout containers for other elements. The same is true for the Grid element: It's a container for tabular data, consisting of other elements. As you have seen, XAMLPad immediately validates any XAML you enter, and displays it in red if an error is encountered, along with an error message in the lower pane. You better get used to the red color because you will be seeing it a lot during your first experiments with XAML.

So, you need to add an appropriate element for your text. Opt for TextBlock—an element for simple text output. By enclosing the text with the corresponding starting and ending tags, you get the following code:

  <Grid xmlns="http://schemas.microsoft.com/winfx/avalon/2005">
    <TextBlock>Hello world!</TextBlock>
  </Grid>

and finally, the desired output in the upper pane:

[img008.jpg]

Attributes

Your "Hello, world!" message is not very prominent, however. Maybe you should use a larger font size to display it. Remember how this was done with the GDI? You had to:

  • Create a new LOGFONT structure and fill in the required fields
  • Create a font object from the LOGFONT structure by calling CreateFontIndirect() (alternatively, you could use CreateFont() and pass all 14 parameters...)
  • Select the font into the DC via SelectFont() or SelectObject(), remembering the previously selected font in a HFONT variable
  • Draw the text with an appropriate function like DrawText() or TextOut()
  • Reselect the previous font into the DC
  • Delete the font object

The corresponding C/C++ code would look something like the following (and it doesn't include any error checking code, like whether CreateFontIndirect() succeeded, and so forth):

  LOGFONT lf  =
  {
    -48,                    // lfHeight
    0,                      // lfWidth
    0,                      // lfEscapement
    0,                      // lfOrientation
    FW_NORMAL,              // lfWeight
    FALSE,                  // lfItalic
    FALSE,                  // lfUnderline
    FALSE,                  // lfStrikeOut
    ANSI_CHARSET,           // lfCharSet
    OUT_DEFAULT_PRECIS,     // lfOutPrecision
    CLIP_DEFAULT_PRECIS,    // lfClipPrecision
    DEFAULT_QUALITY,        // lfQuality
    FF_DONTCARE,            // lfPitchAndFamily
    "Arial"                 // lfFaceName
  };

  HFONT hLargeFont = CreateFontIndirect(&lf);
  HFONT hOldFont = (HFONT)SelectObject(hdc, hLargeFont);

  LPCTSTR szText = _T("Hello, world!");

  TextOut(hdc, 20, 20, szText, _tcslen(szText));

  SelectObject(hdc, hOldFont);
  DeleteObject(hLargeFont);

In XAML, in contrast, using a different font size is as easy as adding an attribute to the TextBlock element:

  <Grid xmlns="http://schemas.microsoft.com/winfx/avalon/2005">
    <TextBlock FontSize="48">Hello world!</TextBlock>
  </Grid>

Here's the result:

[img009.jpg]

Note that XAML attributes are nothing else than the well-known XML attributes. They are included in the starting tag, always in the form attributeName="attributeValue", with the value enclosed in quotes. XAML elements map directly to objects from the Avalon class hierarchy, and attributes correspond to their properties. For example, if you look at the MSDN WinFX documentation, you will find the class TextBlock in the System.Windows.Controls namespace, and one of its properties is FontSize.

In much the same way, you can add more attributes to further influence the displayed output:

  <Grid xmlns="http://schemas.microsoft.com/winfx/avalon/2005">
     <TextBlock FontSize="48" FontFamily="Comic Sans MS"
                FontWeight="Bold" FontStyle="Italic"
                Foreground="Beige"
                Background="#00005D">
        Hello world!
     </TextBlock>
  </Grid>

This is what you see in XAMLPad:

[img010.jpg]

Note the two different ways of specifying colors here: For the foreground, I used the color name "Beige," one of the 141 predefined color names from the System.Drawing namespace. Besides the more obvious color names like "Red," "Yellow," and "DarkGray," there are many more fancy color names, things like "BlanchedAlmond," "HotPink," and "CornflowerBlue"—lots of room for play!

For the background, I used the hexadecimal RGB notation, prefixed by #, and a hex string of six characters that describe the red, green, and blue components of the color, respectively. If you know HTML, this notation will be familiar to you. Just for the record, a lot more is going on behind the scenes: If you look up the MSDN documentation for TextBlock's Foreground property, you will see that it is not a System.Drawing.Color, but a Brush (from the System.Windows.Media namespace. Further investigation reveals that Brush is an abstract base class with three derived classes: GradientBrush, SolidColorBrush, and TileBrush. Only SolidColorBrush has a constructor that takes a Color object as its sole parameter. So, what actually happens when you assign "Beige" as the Foreground attribute value is that "Beige" is recognized as a constant that corresponds to the RGB value RGB(245, 245, 220), or #F5F5DC in hexadecimal notation. The only constructor that takes that type is the one from SolidColorBrush, so a SolidColorBrush object will be instantiated, initialized with that value, and assigned to the Foreground property (which is of the abstract type Brush). However, there's much, much more to colors and brushes in Avalon—I'll get back to that later on. Just a word about the font family name: If a font with the name you specified here is not found among the installed fonts, setting that property will fail silently: The XAML remains valid, and a font which best matches the other specified font attributes is used instead.

2D Graphics

Now, let's get away from "Hello, world!" and explore some other Avalon elements: The basic 2D graphics shapes like rectangles, lines, and ellipses. Although you could continue using Grid as the root element, you will use Canvas now. Canvas is particularly useful when you need to place shapes and other drawing elements at absolute positions. An interesting thing is that Canvas elements can be nested: That way, you can prepare part of a drawing in a canvas, and then insert that entire drawing as a single element into another canvas, applying transformations like scaling or rotation to it.

Here's a piece of XAML that creates a Canvas element displaying a thick, green, diagonal line:

  <Canvas xmlns="http://schemas.microsoft.com/winfx/avalon/2005">
    <Line Stroke="ForestGreen"
          StrokeThickness="10"
          StrokeStartLineCap="Round"
          StrokeEndLineCap="Flat"
          X1="1.5cm" Y1="0.45cm"
          X2="280px" Y2="1.2in"/>
  </Canvas>

Note the different syntax for the Line element: Because it doesn't contain any text content or child elements, you don't need a starting and ending tag, but can use a short-hand way to create an empty tag: Instead of <Line> </Line>, you simply write <Line/>—the two are equivalent. Another thing you can see here are units: The coordinates for the starting and ending points of the line can be specified in pixels (px), centimeters (cm), or inches (in). If you omit the unit (as in the StrokeThickness attribute), pixels will be implied. Also note the decimal values: All coordinates (and many other values, like transparency, angles, scaling factors, and so on) in Avalon are double precision values. Imagine how nicely you can create device-independent output that way—just use real-world units, and the Avalon rendering engine will make sure that everything will be rendered in the correct sizes, regardless of whether you are drawing to the screen or printing! Compare that to the GDI, where you could use mapping modes like MM_HIMETRIC or MM_LOENGLISH, but had to specify coordinate values in weird units like 0.1 mm or 0.001 inches because the GDI generally uses integers.

Here's the output in XAMLPad:

[img011.jpg]

The StrokeStartLineCap and StrokeEndLineCap properties specify how the line ends of an open shape will be rendered, possible values are Round, Flat, Square and Triangle.

Let's add a few more shapes:

  <Canvas xmlns="http://schemas.microsoft.com/winfx/avalon/2005"
          Background="Linen"> 

    <!-- Green Line -->
    <Line Stroke="ForestGreen"
          StrokeThickness="10"
          StrokeStartLineCap="Round"
          StrokeEndLineCap="Flat"
          X1="1.5cm" Y1="0.45cm"
          X2="280px" Y2="1.2in"/>

    <!-- Golden circle with blue border -->
    <Ellipse Stroke="SteelBlue"
            StrokeThickness="5"
            Fill="Gold"
            CenterX="4cm" CenterY="3cm"
            RadiusX="2.3cm" RadiusY="2.3cm"/>

    <!-- Red triangle -->
    <Polygon Points="290,220 240,130 20,150"
            Fill="Tomato" />

    <!-- Semi-transparent rectangle -->
    <Rectangle Stroke="DarkBlue"
              Fill="DarkGray" Opacity="0.4"
              Canvas.Left="1.2in"
              Canvas.Top="0.8in"
              Width="1.4in" Height="1.5in"/>
  </Canvas>

Most of what you added is pretty self-explanatory, and here's what you'll see if you type (or copy and paste) the above XAML into XAMLPad:

[img012.jpg]

Although I doubt that you can expect to see my masterpiece in the Metropolitan Museum of Modern Art some time in the near future, it should be sufficient to demonstrate some additional XAML features.

A few things are worth mentioning: First, note how overlapping shapes cover each other: The visible Z-order of shapes on a canvas is determined simply by the order in which they appear in the XAML code; the last elements are drawn on top of others. Second, note how you can draw a closed Polygon (or an open PolyLine element) by specifying a list of points, separated by commas, as pairs of x- and y coordinates in the Points attribute—here, you used three points (six values) to draw a triangle. Because you omitted the Stroke attribute, no border is drawn. Next, take a look at the Opacity attribute you have specified for the Rectangle element: An opacity value of 0 means fully transparent, while 1 means completely opaque. Hence, Opacity="0.4" makes the rectangle 40% opaque, and you can see how the objects underneath shine through. Note that this is only one way of creating transparent objects; others that you'll see later include specifying an alpha value in an ARGB quad, or the use of transparent brushes.

An important thing to note is the way the position of the rectangle has been specified: You are using Canvas.Left and Canvas.Top here. Actually, if you look at the documentation, you will see that Rectangle has no Left/Top or X1/Y1 properties. The normal way to position drawing elements on a Canvas is to specify their absolute positions from the left, top, right, or bottom of the Canvas bounds, by using Canvas.Left, Canvas.Top, Canvas.Right, or Canvas.Bottom. What you have previously seen when you drew an ellipse by its CenterX and CenterY attributes, or a line by its X1/Y1 and X2/Y2 pairs is an additional way to position those elements relative to their absolute canvas position. In the previous examples, that absolute position just happened to be 0/0 from the top left (because you didn't specify it) so the additional, relative positioning information behaved like an absolute position. If you find that confusing, I agree with you—there's some degree of inconsistency here, and I hope that it will be cleaned up before the final release.

A final detail is the changed background color of the canvas, which you achieved by setting its Background attribute to "Linen." Also note the comments: The can be added inside <!--  --> tags just as in any other XML code.

I'll leave it at that for the moment. In the next part of this series, I'll shed some light on the Avalon control classes for creating GUIs (panels, buttons, labels, text boxes, list controls, and so forth) Furthermore, you'll be seeing some more interesting graphics effects like gradient fills and transparency. You'll also have a first look at how to create Avalon applications in Visual Studio (using C# for the moment) and understand how XAML code is integrated into .NET projects. Besides all that, you will be putting your knowledge to practice by building a sample application:

The CodeGuru Clock

In the following articles of the Avalon series, although I will show you how to create Avalon applications with Visual Studio 2005 and introduce more Avalon classes and their corresponding XAML elements, you will also go through the steps of developing a small yet complete sample application with Avalon: The CodeGuru desktop clock.

[img013.jpg]

One goal will be to do as much as possible of the user interface in XAML, and use code-behind in C# only where required—quite a challenge for some of the features, as you will see! Of course, the clock is not only fully functional and scalable, but will also take advantage of Avalon's speech recognition and synthesis capabilities, so the clock will listen to your spoken commands and talk back to you. Stay tuned!



About the Author

Guido Stercken-Sorrenti

Guido is a freelance software developer and consultant, specializing mainly in graphics software and UI design, and has been using Visual C++, MFC and the GDI for more than ten years. As a regular contributor to the CodeGuru forums, he has been awarded MVP (Most Valuable Professional) by Microsoft in 2005 and 2006. He currently spends much time exploring Avalon, the new graphics subsystem of the future Windows platforms.

Comments

  • There are no comments yet. Be the first to comment!

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Best-in-Class organizations execute on a strategy that supports the multi-channel nature of customer requests. These leading organizations do not just open up their service infrastructures to accommodate new channels, but also empower their teams to deliver an effective and consistent experience regardless of the channel selected by the customer. This document will highlight the key business capabilities that support a Best-in-Class customer engagement strategy.

  • The first phase of API management was about realizing the business value of APIs. This next wave of API management enables the hyper-connected enterprise to drive and scale their businesses as API models become more complex and sophisticated. Today, real world product launches begin with an API program and strategy in mind. This API-first approach to development will only continue to increase, driven by an increasingly interconnected web of devices, organizations, and people. To support this rapid growth, …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds