I have been working on XAML language support in our product for over a year now. In that time, I have had to dig into all sorts of XAML details and bang my head against the carefully laid traps subtle differences in behavior between Microsoft’s latest fashionable XAML frameworks.

What finally pushed me to write this post was a story involving x:FieldModifier. This XAML attribute controls the accessibility of the field generated for an element with an x:Name attribute. Its twin, x:ClassModifier, also makes an appearance: it controls the accessibility of the type declared by the XAML file itself. Will your UserControl be public, or hidden away as internal?

The usefulness of x:FieldModifier is questionable to begin with. If I create a window or page and put a button on it with the wonderfully descriptive name btn1, why would I want its field to be anything other than private or protected? These fields are mutable, too. If somebody decides to change one from outside, things can go spectacularly wrong.

Then there is another question: which attribute values are valid? XAML frameworks support different languages for the code-behind portion of a XAML file, if it has one, and those languages — read C# and VB.NET — use slightly different names for access modifiers. Think Friend in VB.NET versus internal in C#. I cannot imagine why the designers of the first versions of XAML for WPF did not define a set of values for x:FieldModifier and x:ClassModifier independent of the code-behind language, using the basic access levels available in CLI languages: public, internal, protected, and private.

Still, those design decisions were made a long time ago, even if IDE tooling and common sense lost out. We have to live with them: parse the values correctly, highlight invalid ones, assign the right accessibility to the synthetic fields created from elements with x:Name, offer sensible attribute completion, and so on. The implementation in our product is actually very simple, was written about four years ago, and has given us no reason to worry.

Then along comes a new XAML framework, which I do not even know what to call after the recent legal fuss over the word “Metro”. The project type in Visual Studio was originally called “Metro style application”, then renamed “Windows Store application” shortly before release. What exactly does the Store have to do with it? Meanwhile, my Twitter feed is full of references to “Windows 8 style applications”. I will call it “WinRT XAML”, because all these awful names obscure the actual point: the XAML subsystem is written in native code, built directly into Windows 8, and exposed through WinRT, the fashionable new object-oriented system API that is sort of just as fundamental to the OS as the great and terrible Win32 API.

Surprisingly, despite being written in native code, WinRT XAML differs from Silverlight XAML and its profiles, such as WP7, less than it might have. But the differences are there, sprinkled evenly across the entire framework. Some are improvements. Others include new namespace reference syntax that makes any existing XAML code impossible to move to WinRT XAML without changes. How lovely.

Recently, I got a request about a change in the behavior of x:FieldModifier in WinRT XAML. Fields are now private by default when no explicit modifier is specified. In WPF and every Silverlight framework, they defaulted to internal. Why? Why on earth did anyone make them internal??? The change is an improvement in one sense, but it raises questions: why introduce a breaking change that could make porting code harder? Why private rather than protected?

Okay, I accept the inevitable and implement the correct default access modifiers for WinRT XAML. Then something makes me check what happens if I write Public with C# code-behind. It does not work in WPF or Silverlight, but in WinRT XAML the damn thing works! The generated portion contains public, in the correct case, and is perfectly valid C#. The MSDN page says that case sensitivity and the conversion of strings into access modifiers are handled by the language’s CodeDOM provider. Why would that provider behave differently for WinRT? Most likely, the WinRT XAML compiler does not use CodeDOM at all…

Okay, I add parsing that ignores case for access modifiers in WinRT XAML. I do not want our support painting the user’s code red when they write x:FieldModifier="PUBLIC" in capitals and the project builds and runs just fine. Now I am curious about how the WinRT XAML compiler handles different languages. I write x:FieldModifier="Friend" in a C# project, and the build fails because friend has found its way into the generated C# code. Right. The WinRT XAML compiler apparently has a hardcoded set of modifiers: the union of the C# and VB.NET keywords. Instead of rejecting a keyword that belongs to the wrong language, it passes it straight through to the generated code, correcting the case if necessary. In other words, you can write internal in WinRT XAML with VB.NET code-behind; the XAML compiler swallows it, and the VB.NET compiler chokes. How would you extend this to another language? A mystery. My guess: you would not. And then I realize that our own XAML support is not ignoring case for VB.NET code-behind either…

Okay, I fix that annoying oversight, more or less reproducing the logic of the CodeDOM providers. The fix is simple and clean. The depressing part is that I have to check every such fix N * M times, where N is the number of major XAML frameworks — WPF, SL5, WinRT, sometimes WP7, sometimes WPF 3.5 and 4 separately — and M is the number of code-behind languages: C# and VB.NET.

Okay, access modifiers in XAML with VB.NET code-behind are indeed always checked without regard to case. Now it is time to check x:ClassModifier support another N * M times. The first discovery: WinRT XAML does not have an x:ClassModifier attribute at all…

Okay, I remove x:ClassModifier from completion specifically for WinRT XAML, and stop using it to determine the accessibility of types declared in XAML. In a way, this is an improvement, even though it breaks compatibility. Unlike the WPF and Silverlight compilers, the WinRT XAML compiler emits no access modifier at all on the generated partial class declaration. This means you can change the accessibility of the entire type just by changing the modifier in the code-behind. In WPF and Silverlight, you also have to set the matching x:ClassModifier in the XAML, which is rather inconvenient. It also means that, for a XAML file with no code-behind, you cannot change the accessibility at all: the type will always be internal, according to C#’s rules. I dread to think what happens if another language has different defaults.

Okay, through gritted teeth, I finish implementing support for “the absence of x:ClassModifier” specifically in WinRT XAML. Thank the universe our model makes this easy: the XAML file can simply represent a partial declaration with no explicit access modifier. But the story does not end there, because testing Silverlight finishes off my remaining nerve cells:

A Silverlight VB.NET project using internal for x:ClassModifier but friend for x:FieldModifier

I have run out of “okay,” too. The helpful CodeDOM provider — the screenshot shows a XAML file in a VB.NET project — correctly validates x:FieldModifier and accepts Friend for assembly-level access. Then something incredible happens: in the almost identical x:ClassModifier attribute, Friend is suddenly invalid, and the XAML compiler demands C#’s internal instead. Arrrrgh. Except, for some reason, it ignores case, which C# certainly does not. ARRRRRGH! Naturally, WPF with VB.NET has no such problem. This is most likely a plain old bug. And how exactly am I supposed to support this?

Let me try to extract a moral from this story. Yes, these problems will probably never affect ordinary XAML developers, and their consequences are not particularly serious. Even so, they tell us something about the people who designed XAML in the first place, and about the design, quality, attention to detail, and testing of today’s XAML frameworks.

I honestly do not understand how anyone let the XAML frameworks become this fragmented: such subtle yet pervasive incompatibilities, sometimes making code completely impossible to port. How do bugs survive in something as fundamental as access modifiers? How did the development stacks and framework profiles become such a maze for developers? Where is all this heading? Which of these frameworks will not be dying in agony five years from now? And why, in 2012, does the most advanced IDE in the world need a project that builds just to provide code completion, for crying out loud?

The only thing that keeps me working on XAML support is the belief that we can beat back enough of this evil to keep shipping developers a better tool.