Part 3 - Introduction to XAML
Download the source code for this lesson at http://absolutebeginner.codeplex.com/
In this lesson, I want to talk about the XAML syntax we wrote in our first pass at the HelloWorld app. Hopefully you could see how the XAML we wrote impacted what we saw in the Phone preview pane. It's relatively easy to figure out the absolute basics of XAML just by looking at it, however I want to point out some of its features and functions that may not be obvious at first glance.
At a high level, our game plan in this lesson:
(1) We'll talk about the purpose and nature of XAML, comparing it to C#
(2) We'll talk about the special features of XAML ... little hidden features of the language that may not be obvious by just staring at it
My aim is by the end of this lesson you'll have enough knowledge that you can look at the XAML we write in the remainder of this series and be able to take a pretty good guess at what it's doing before I even try to explain what it does.
What is XAML?
In the previous lesson, I made a passing remark about XAML and how it looks similar to HTML. That's no accident.
XAML is really just XML, the eXtensible Markup Language. I'll explain that relationship in a moment, but at a higher level, XML looks like HTML insomuch that they share a common ancestry.
Whereas HTML is specific to structuring a web page document, XML is more generic. By "generic" I mean that you can use it for any purpose you devise and you can define the names of the elements and attributes to suit your needs. In the past, developers have used XML for things like storing application settings, or using it as a means of transferring data between two systems that were never meant to work together. To use XML, you define a schema, which declares the proper names of elements and their attributes. A schema is like a contract. Everyone agrees — both the producer of the XML and the consumer of the XML to write and read XML to conform to those rules, they’ll abide by that contract. Now, they can communicate with each other. So, a schema is an important part of XML. Keep that in mind … we’ll come back to that in a moment.
XAML is a special usage of XML. Obviously, we see that, at least in this case, XAML has something to do with defining a user interface in our Phone's interface. So in that regard, it feels very much like HTML. But there’s a big difference … XAML is actually used to create instances of classes and set the values of the properties. So, for example, in the previous lesson we defined a Button control in XAML:
<Button Content="Click Me"
Comment out button by enclosing it in the following syntax:
And in the MainPage.xaml.cs, change the OnNavigatedTo method to look like this:
protected override void OnNavigatedTo(NavigationEventArgs e)
// TODO: Prepare page for display here.
Button myButton = new Button();
myButton.Name = "clickMeButton";
myButton.Content = "Click Me";
myButton.Width = 200;
myButton.Height = 100;
myButton.Margin = new Thickness(46, 102, 0, 0);
myButton.HorizontalAlignment = Windows.UI.Xaml.HorizontalAlignment.Left;
myButton.VerticalAlignment = Windows.UI.Xaml.VerticalAlignment.Top;
myButton.Background = new SolidColorBrush(Colors.Red);
myButton.Click += clickMeButton_Click;
I've added this C# code in the OnNavigatedTo() method of my MainPage class. I'll talk about the relationship between the MainPage.xaml and MainPage.xaml.cs in just a moment, but we've already seen how we can define behavior by writing procedural C# code in the MainPage.xaml.cs file. Here, I'm merely writing code that will execute as soon as a new instance of the MainPage class is created by writing the code in the constructor of that class.
The important take away is this: XAML is simply a way to create instances of classes and set those objects' properties in a much more simplified, succinct syntax. What took us 10 lines of C# code we were able to accomplish in just one line of XAML (even if I did separate it on to different lines in my editor, it's still MUCH SHORTER than it would have been had I used C# to create my objects.
Furthermore, using XAML I have this immediate feedback in the Phone preview pane. I can see the impact of my changes instantly. In the case of the procedural C# code I wrote, I would have to run the app each time I wanted to see how my tweaks to the code actually worked.
Introducing Type Converters
If you have a keen eye, you might notice the difference in the XAML and C# versions when it comes to the HorizontalAlignment attribute / property …
If you tried:
myButton.HorizontalAlignment = “Left”;
… you would get a compilation error. The XAML parser will perform a conversion to turn the string value "Left" into the enumeration value Windows.UI.Xaml.HorizontalAlignment.Left through the use of a Type Converter.
A Type Converter is a class that can translate from a string value into a strong type — there are several of these built into the Phone API that we’ll use throughout this series. In this example, the HorizontalAlignment property, when it was developed by Microsoft’s developers, was marked with a special attribute in the source code which signals to
the XAML parser to run the string value through a type converter method to try and match the literal string "Left" with the enumeration value Windows.UI.Xaml.HorizontalAlignment.Left.
Just for fun, take a look at what happens when you attempt to misspell “Left”:
(In the XAML misspell 'Left')
… you’ll get a compilation error because the Type Converter can’t find an exact match that it can convert into the enumeration value Windows.UI.Xaml.HorizontalAlignment.Left.
So, the first characteristic of XAML is that it is a succinct means of creating instances of classes. In the context of building a Phone application, it is used to create instances of user interface elements, it could be used for other purposes in other technologies.
Understanding XAML Namespace Declarations
Next, let's talk about all that XAML code at the very top of the MainPage.xaml file ... we ignored it until now.
At the very top of the file, we see the following:
While you're looking this over, remember what I said a moment ago -- about schemas being a part of XML. If that's the case, then where does this XAML promise to adhere to a schema?
See lines 3 through 7 ... there are five schemas this MainPage.xaml is promising to adhere to. Each of them are defined with the xmlns attribute. The first xmlns defined in line 3 is the default namespace -- in other words, there's no colon and no word after the colon like you see in lines 4 through 7.
The rest of the namespaces in lines 4 through 7 will use name / colon combination. So, just to be clear ... the :x or :phone is the NAMESPACE, that is associated with a SCHEMA (what we've called a contract). Each element and attribute in the rest of this MainPage.xaml MUST ADHERE TO AT LEAST ONE OF THESE SCHEMA's, otherwise the document is said to be invalid. In other words, if there's an element or attribute expressed in this XAML file that is not defined in one of these namespaces, then there's no guarantees that the compiler -- the program that will parse through our source code and create an executable that will run on the Phone -- the compiler will not be able to understand how
to carry out that particular instruction.
So, in this example:
We would expect the TextBlock element and attribute Background to be part of the default schema corresponding with the default namespace defined at the location in line 3.
However, x:Name is part of the schema corresponding with the x: namespace defined at the location in line 4.
I have a bright idea ... let's try to navigate to default namespace to learn more about what makes up a namespace in the first place:
Note: This will fail when you try it!
s because the schema is not published in the sense that you can go to that URL and view it. Instead, a schema is simply a unique name, similar to how we used Namespaces in C# to identify two classes that may have the schema (and therefore, the namespace in our XAML) keeps class names sorted out, kind of like a last name or surname.
This URL, or more properly, we should refer to it as a URI (Uniform Resource IDENTIFIER … rather than LOCATOR) is used as a namespace identifier. The XML namespaces are instructions to the various applications that will parse through the XAML … the Windows Runtime XAML parser will be seeking to turn it into executable code, while the Visual Studio and Blend designers will be seeking to turn it into a design-time experience.
So, the second XML Namespace defines a mapping, x: as belonging to this schema:
Therefore, any elements or attribute names that are preceded by the x: prefix means that they adhere to this second schema.
s subtle, but the second schema defines the intrinsic rules for XAML in general. The first schema defines the contract / rules for Phone specific usage of XAML. In other words, the fact that we can work with the Grid, Button, TextBlock and the other XAML elements without using a prefix means that they are defined in the default namespace.
Line 5 is the local namespace … this is the top most namespace for our project. So, any custom classes we create and want to reference, we can just append local: in front.
Lines 6 & 7 define namespaces and schemas that are used to allow Visual Studio's Phone Preview Pane on the left to
display properly. These instructions are ignored at runtime, which is what line 8 is doing -- when compiling the XAML code, ignore anything prefixed with :d.
we could spend a lot of time talking about the specifics, but the main takeaway is that this code at the very top of each XAML file you add to your phone project does have a purpose, it defines the rules that your XAML code must follow. You'll almost never need to modify this code, but if you remove it, you could potentially break your application. So, I would encourage you to not fiddle around with it unless you have a good reason to.
The final attribute sets a theme resource for the page. I’ll talk about that in an upcoming lesson on Themes and Styles.
Understanding the relationship between the .xaml and .xaml.cs files
s Solution Designer, you can see that the XAML files have an arrow which means that we can expand them to reveal a C# file by the same name, the only difference is that it has a .cs file name extension appended to the end. If you look at the ll see that it defines a MainPage class, and furthermore, it defines it as a PARTIAL class.
public sealed partial class MainPage : Page
The other half of the equation is defined in lines 1 & 2 of the MainPage.xaml:
While it doesn't use the term Partial like it's procedural counterpart, it does indicate the relationship between the two.
Why is this important? This relationship means that the compiler will combine the output of the MainPage.xaml and the MainPage.xaml.cs files into a SINGLE CLASS. This means that they are two parts of a whole. That’s an important concept … that the XAML gets compiled into Intermediate Language just like the C# gets compiled into Intermediate Language and they are both partial implementations of a single class. This allows you to create an instance of a class in one file then use it in the other file, so to speak. This is what allows me to create an instance of the Button class called clickMeButton in XAML and then call its methods or set its properties in C#. We’ll see more examples of this later in this lesson.
Understanding Default Properties
Since XAML is essentially an XML document, we can embed elements inside of other elements. We've already seen an example of this:
<Button ... />
<TextBlock … />
Here Page "contains" a Grid and the Grid "contains" a Button and a TextBlock. Or, perhaps more correctly in XAML parlance, that Page’s Content property is set to Grid, and Grid's Children collection includes the Button and TextBlock. Depending on the type of control you're working with, the default property can be populated using this embedded style syntax. So, you could do this:
<TextBlock Content="Click Me" ... />
... or this ...
... since the Content property is the default property of the Button class.
Understanding Complex Properties and the Property Element Syntax
In some cases, merely setting attribute values masks the complexity of what's going on behind the scenes. A good example of this is setting Background="Red". We've already seen this procedurally in C# -- to accomplish the same thing:
myButton.Background = new SolidColorBrush(Colors.Red);
... we have to create a new instance of a SolidColorBrush and pass in an enumerated Colors value. This is another great example of a property type converter that we learned about earlier in this lesson. But some attributes are simply too complex to be represented as attributes.
When a property is not easily represented as a XAML attribute, it's referred to as a "complex property". To demonstrate this, first I'm going to remove the Background="Red" attribute from the Button, remove "Hello World!" as the default property, and add it back with a Content="Hello World!" attribute:
Next, in the Properties pane, I'm going to set the Background property to a linear gradient brush.
(1) I select the Brush property to reveal the Brush editor.
(2) I make sure that Background is selected.
(3) I select the Linear Brush tab (middle tab).
(4) I move the selector all the way to the upper-right hand side of the color editor.
I should now see that the button has a black-to-red color gradient. But more importantly, let's look at the XAML that was generated by the Brush editor:
The XAML required to create that background cannot be easily set in a simple literal string like before when we simply used the word "Red". Instead, notice how the Background property is broken out into its own element:
<Button ... >
This is called "property element" syntax and is in the form <Control.Property>.
A good example is the LinearGradientBrush. The term “brush” means that we’re working with an object that represents a color or colors. Think of “brush” like a paint brush … this particular paint brush will create a gradient that is linear — the color will change from top to bottom or left to right. Now, admittedly, you would NEVER want to do what I’m doing in this code example because it goes against the aesthetic of all Windows Phone applications. But, let’s pretend for now that we’re expressing our individuality by using a gradient color as the background color for a Button.
As you can see (below), if we want to define a LinearGradientBrush, we have to supply a lot of information in order to render the brush correctly ... the colors, at what point that color should break into the next color, etc. The LinearGradientBrush has a collection of GradientStop objects which define the colors and their positions in the gradient (i.e., their "Offset").
However, the XAML representing the LinearGradientBrush in the code snippet above is actually SHORTENED automatically by Visual Studio. Here's what it should be:
<GradientStop Color="Red" Offset="1" />
<GradientStop Color="Black" Offset="0" />
Notice how the <LinearGradientBrush.GradientStops> and <GradientStopCollection> elements were omitted? This is done for conciseness and compactness and is made possible by an intelligent XAML parser. First of all, the GradientStops property is the default property for the LinearGradientBrush. Next, GradientStops is of type GradientStopCollection and implements IList<T>, the T in this case would be of type GradientStop. Given that, it is possible for the XAML parser to deduce that the only thing that could be nested inside the <LinearGradientBrush ... /> is one or more instances of GradientBrush, each being implicitly .Add()'ed to the GradientStopCollection.
So the moral of the story is that XAML allows us to create instances of classes declaratively, and we have a granular fidelity of control to design user interface elements. Even so, the XAML parser is intelligent and doesn’t require us to include redundant code — as long as it has enough information to create the object graph correctly.
To recap, we've learned about the syntax of XAML. Most of XAML is pretty straightforward, but there are a few things that are not quite as obvious.
(1) XAML is simply an implementation of XML, and relies heavily on schemas and namespaces to adhere to "contracts" so that different applications can create, interpret, display or compile the XAML code.
(2) The purpose of XAML is to allow for a compact, concise syntax to create instances of classes and set their properties. We compared the procedural version of a button created in C# versus one created declaratively in XAML and saw how much less code was required.
(3) XAML requires less code due to its built-in features like property type converters which allows a simple string value be converted into an instance of a class.
(4) For more complex property settings, XAML offers property element syntax which harnesses the intelligent XAML parser to rely on default properties and deduction to reduce the amount of XAML code required to express a design.
(5) We learned about the embedded syntax style and the embedded nature of elements which suggests a relationships between visual elements. For example, the Phone contains a Grid for layout, which in turn contains input or other types of controls. These are represented with opening and closing elements representing containment or ownership.
(6) We learned about default properties; each control has a default property which can be set using that same style of embedded syntax.
Next, let's learn more about the Grid for layout, we'll learn about XAML's attached property syntax and how events are wired up in the next lesson.