Parser.LoadXml

Someone asked me the other day about why in the May CTP the documentation for Parser.LoadXml says, "Using SaveAsXml for common serialization scenarios is not recommended."  This is my fault, I asked the SDK team to warn people that its it's very easy to paint yourself into an architectural corner using SaveAsXml, but I didn't elaborate further. 

Here's what I meant.  Most people who I've talked about SaveAsXml want to do one of three things:

  • server-side generation of xaml
  • Clipboard/drag-and-drop
  • graphical designer tool

Using SaveAsXml for server-side generation is just a bad idea, Avalon is client software, not server software, and server software has entirely different requirements for performance, scalability, and robustness.  You need a completely different architecture for that -- eg, MSHTML vs. ASP.
 
SaveAsXml for Clipboard/drag-and-drop scenarios is mostly straightforward, although we don't handle images so good, because how do you stick an image inside a text file?  (This is solvable, your feedback appreciated so we can prioritize appropriately)
 
SaveAsXml for graphic designer tools is, well, complicated.  Writing designers is hard, and SaveAsXml can let you forget that -- you can get 80% of what you want fairly easily, only to discover that last 20% requires a different architecture.  The 80% solution is you just create a bunch of elements and set properties on them, then call SaveAsXml.  But you'll run into a number of problems:
 
SaveAsXml produces ugly, ugly output.  With some work we can get that down to just one "ugly", but we will never support source code preservation (SCP), where we don't change the way you capitalized and spaced things when you hand-edited the file.  That's because loading the file into memory is a lossy process -- once we've built the element tree, we've forgotten what your original markup looked like.
 
Actually, this lossy load comes up several other places.  Consider <Image Source="foo.jpg"/>  -- when SaveAsXml is called, we've long since forgotten whether that bitmap came from foo.jpg or bar.jpg.  Similarly, {StaticResource foo} is turned into a pointer without a name.  And event handlers are ignored completely, there's no way to serialize an arbitrary delegate (although you could probably hack up some common special cases).
 
Finally, there's the "shadow property" problem.  Simply put, what you show on the screen isn't always what you want to serialize.  Consider a disabled button -- if it was really disabled, you couldn't click on it, so what a designer tool does is create a button that looks disabled but isn't, and then come serialization time, says "this element may not be disabled but I want you to serialize that it is."
 
The general approach that I've seen be successful (and there may be others) is to associate a design time object with each element (for anyone who's worked with the Windows Forms designer, this is the approach they use, they call that design time object a "designer").  The element is what you show on the screen, the design time object maintains information you need to serialize (usually stored as a special case list -- i.e., serialize what's in the element, except these three things).  Then, you need to hook the serialization process to get this design-time object involved, and similarly when you load the file into the designer, you need to store off key bits of information such as image filenames.  What gets really complicated is that for those last two parts, the Avalon parser and serializer don't have a lot of hooks for this right now (especially the LoadXml part).  We're working on the serialization part by involving TypeDescriptors in the serialization process (notice the WinForms influence?), although that unfortunately won't be ready for several months.  As for the parser half, we don't currently have plans to add any new hooks, so I'd really appreciate your feedback there if we need something.  One of the reasons we haven't put more hooks into the parser is that we found really hard-core designer tools end up abandoning the Avalon parser completely for issues like source code preservation, so building such hooks into the Avalon parser has seemed like a no-win effort to us, but I'd love your feedback on your scenarios.  Thanks.