Charles Petzold

Introducing XAML Cruncher 2.0

July 10, 2007
Roscoe, N.Y.

XAML Cruncher is a WPF program that lets you experiment with writing XAML. Much like the XAMLPad program included with the .NET 3.0 SDK, XAML Cruncher contains an Edit section to write XAML and a Display section that displays the rendered graphics. The editor and most of the menu is Notepad-compatible. The source code is included in my book Applications = Code + Markup.

I like writing XAML by hand, so I spend a lot of time in XAML Cruncher, perhaps even more than in Visual Studio.

I have just published XAML Cruncher 2.0, which includes enhancements I added in connection with my forthcoming book 3D Programming for Windows. Apparently I did not publish the original with the "automatic update" option, so you need to explicitly install the new version from the WPF page of my Web site:

Or you can just start the ClickOnce installation from here:

That's the same location as XAML Cruncher 1.0. If you have XAML Cruncher 1.0 already installed, it won't be replaced (at least that was my experience) so you may want to manually uninstall it from the Control Panel.

If you've used XAML Cruncher as much as I have, you probably know that with long use it can slow down a lot — particularly if you're experimenting with animation. One thing that obviously helps is selecting the Suspend Parsing item from the Xaml menu. With XAML Cruncher 2.0 I haven't fixed the problem entirely (nor have I entirely figured out all the causes of the problem), but I've made a little headway.

Normally, with every keystroke in the Edit section, XAML Cruncher calls XamlReader.Load to convert the XAML file into a visual tree. Everything in the previous visual tree is abandoned and then becomes eligible for garbage collection. However, until that happens there may still be animations going on in abandoned objects, and that could slow things down. XAML Cruncher 2.0 tries to avoid this problem by explicitly calling GC.Collect when abandoning the previous visual tree.

If there's an error in the XAML file, then XamlReader.Load raises an exception. However, it might have already parsed part of the XAML file and created a bunch of objects before encountering a problem. XamlReader.Load will even create objects from a file that does not qualify as well-formed XML before raising an exception! For this reason, XAML Cruncher 2.0 first creates a XmlReader object and parses the entire file by repeating calling the Read method. If that succeeds, then it moves on to XamlReader.Load.

The other enhancements to XAML Cruncher are all in the Xaml menu and are also described in the Help page (which is actually a FlowDocument object):

If you use XAML Cruncher for designing graphical figures, you'll appreciate the Show Ruler and Show Grid Lines options. In keeping with the 96-DPI standard of WPF graphics, I use inches rather than metric.

The Print rendered XAML and Save rendered XAML to bitmap options let you print or save a bitmap image of the visual tree. The logic for these items is based entirely on the Visual object being displayed, so the print or bitmap image will be the same metrical size with the same margins and clipping. The printing code uses the PrintVisual method of PrintDialog and the bitmap code creates a RenderTargetBitmap object.

(When printing 3D figures you can get much better control over the printed rendition by using Viewport3DVisual rather than Viewport3D. See Chapter 9 of my forthcoming book 3D Programming for Windows for details.)

The Save rendered XAML to bitmap dialog lets you specify a metrical height and width of the bitmap and a resolution in dots per inch. You can save in PNG, JPEG, WMP, BMP, TIFF, or GIF formats. (Check the Delete empty rows and columns before save checkbox to get rid of all the "white space" around the object.) Very many of the pictures in 3D Programming for Windows were done with XAML files that I rendered as 400 DPI bitmaps, so they should look pretty good in the book.

I've saved the best new feature for last: I discovered that a XAML filed passed to XamlReader.Load can reference .NET DLLs that are loaded into the application that is calling XamlReader.Load. The new Load Assembly dialog box in XAML Cruncher 2.0 lets you load other DLLs so they are available to the XAML files you're editing. These DLLs are also loaded the next time XAML Cruncher 2.0 starts up until you remove them from the list of loaded assemblies.

I've found this feature to be a great way to interactively test out a new DLL. If you need to recompile the DLL, however, you'll need to end XAML Cruncher, recreate the DLL, and restart XAML Cruncher.

After you've loaded a DLL into XAML Cruncher 2.0, you need to add an XML namespace declaration to the XAML file in the usual manner:

For some DLLs that use the XmlnsDefinition attribute, you might be able to use a URL like this:

However, I noticed a little difference between these two formats that I suspect is a fluke (or feature?) in the XamlReader class. If you load a DLL into XAML Cruncher 2.0, you can then reference that DLL right away in the XAML using the normal ("clr-namespace") namespace syntax. But you can't get at it using the URL namespace syntax. You have to reload XAML Cruncher and start it up again with the loaded DLL. I suspect XamlReader searches loaded DLLs for XmlnsDefinition attributes only once when it's first called by an application.

XAML files that reference other DLLs can't be executed outside of XAML Cruncher, of course, but it's fairly easy to turn them into XBAPs with the addition of an application definition file.