January 25, 2015

Button with << in content

This post is inspired by a question on SO. Its author defined two buttons in XAML in a WPF application, set content of the first one to >> and content of the other one to << through a Content property but the compiler complained and left him puzzled. Why closing brackets can be used but opening ones cannot?

Untitled
My first guess was that
<Button Content="<<" />

is by the compiler translated to
<Button>
<<
</Button>

before processing, because the two forms are equivalent, but after I’ve done some research I found that this is not true. Why would I even think that? Because I know that bracket matching can be easily determined by pushing opening brackets onto a stack and popping them as closing brackets are read by a text reader. Then it’s clear that it’s syntactically incorrect, because the compiler is confused with opening brackets missing their closing brackets. Two closing brackets are not a problem, if there’s nothing on the stack, then it has to be content. It makes sense. So how it is really?

When you try those two snippets in Visual Studio, compiler provides different error messages in both cases.

In the first case:
  • when you point with a mouse cursor on a Button text underlined with a red squiggly or on the brackets, it says: “XML element is not closed”,
  • when you point right after a closing quotation mark of content, it says: “Whitespace is missing.” and 
  • finally, when you point on a closing tag, it says: “The open angle bracket character ‘<’ is not valid in an attribute. It should be written as ‘&lt;’.”.
In the second case:
  • when you point on brackets, it says: “Invalid tag header” and
  • when you point on a closing tag, it says: “Closing tag for element ‘<>’ was not found.”.
Now we see the difference in how are these two forms processed. One thing to notice is that it actually provides a solution in one of the error messages. Still, the question is why it does not work with two opening brackets?

To explain this behavior we need to know the following:

Button is one of content controls, which are simply controls that are constrained to contain a single item. Content controls all derive from System.Windows.Controls.ContentControl, which has a Content property of type Object that contains the single item. Because a content control’s single item can be any arbitrary object, the control can contain a potentially large tree of objects. There just can be only one direct child. [1]

Having this on mind it’s now clear that in the second case the compiler can actually represent a button’s content as a UIElement if it’s syntactically correct (therefore those two error messages implying creation of a new element) or just print a text. In the first case, it can be only plain text or a markup extension ({…}).

[1] – WPF 4 Unleashed, Adam Nathan

No comments:

Post a Comment