Wednesday, March 19, 2014

Part 4 Introduction to X ML [AbsoluteBeginnersSeriesForWindowsPhone8_files]



In this lesson, I want to talk about the XAML syntax we wrote in our first pass at the
SoundBoard 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, but I want to point out some of the features and functions that
may not be obvious at first glance.

At a high level, here's our game plan in this lesson:

1.  We'l  talk about the purpose and nature of XAML, comparing it to C# 
2.  We'l  talk about the special features of XAML ... little hidden features of the language that may not become 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 it.


1. 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 agreesboth the producer of the XML and the consumer of the XML abide by
that contract in order to 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:



... that line of code is roughly equivalent to this in C#:


I've added this C# code in the constructor 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.

At this point, I now have two buttons ... one defined declaratively in XAML that has the
content of "Hello World" and will quack when we click the button, and a new second
button that has the content of "Quack". When we run the application:


we can see only one button. That's because the button we just created procedurally in
C#, in the constructor of the MainPage class, is sitting on top of the first button we
created in the previous lesson in XAML. Just to prove it, I'll add one more line of C#
code that will set a margin on the new Quack button, moving it to the left 210 pixels:


The Margin property of the Button is of type Thickness, a general purpose class that
represents 4 dimensions. In this case, we create a new Thickness class and set it's first
constructor argument to 210 pixels. When we run the application again:


... we can now see both buttons.

The larger issue is that we have two (almost) identical buttons ... one created
declaratively in XAML and the other procedurally in C#.

When I create a new XAML element like so:

<Button></Button>

I'm basically creating a new instance of the Button class.

When I set attributes on the Button element, I'm basically setting properties on the
instance of the Button 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.

2. 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
System.Windows.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 typethere are
several of these built into the Windows 8 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
System.Windows.HorizontalAlignment.Left.

Just for fun, take a look at what happens when you attempt to 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
System.Windows.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 Windows 8 application, it is used to create instances
of user interface elements, however XAML is not just a user interface technologyit
could be used for other purposes in other technologies.

3. Understanding XAML Namespace Declarations
Next, let's talk about al 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 agoabout 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 8 ... there are SIX schemas this MainPage.xaml is promising to
adhere to. Each is defined with the xmlns attribute. The first xmlns defined in line 3 is
the default namespacein other words, there's no colon and no word after the colon
like you see in lines 4 through 8.

The rest of the namespaces in lines 4 through 8 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 compilerthe program that will parse through our source code
and create an executable that will run on the Phonethe compiler will not be able to
understand how to carry out that particular instruction.

So, in this example:

<Grid x:Name="LayoutRoot" Background="Transparent">

We would expect the element Grid 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:

http://schemas.microsoft.com/winfx/2006/xaml/presentation


What?! The schema doesn’t actually exist at that URL! That’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 same namethe 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:

http://schemas.microsoft.com/winfx/2006/xaml

Therefore, any elements or attribute names that are preceded by the x: prefix means
that they adhere to this second schema.

But, what’s the difference? It’s subtle, but the second schema defines the intrinsic rules
for XAML in general. The first schema defines the contract / rules for Windows 8
specific usage of XAML. In other words, the fact that we can work with the Grid, Button,
MediaElement and the other Windows Phone 8 XAML elements without using a prefix
means that they are defined in the default namespace.

Lines 5 & 6 define namespaces and schemas for the Phone and Shell, which are at a
different URI, one that takes is cues from the Microsoft.Phone CLR namespace as
defined in assemblies that were installed on our computers after we installed the
Windows Phone 8 API. As you can see, the very first line:

<phone:PhoneApplicationPage



indicates that the PhoneApplicationPage class itself is part of this definition. The
PhoneApplicationPage derives from Windows.System.Controls.Page ... that just
happens to be the same class that is a parent to Windows Presentation Foundation
page classes, and Windows Store app page classes. It has a lot of the base
functionality shared by all three of these project types. So, the upside is that you're able
to leverage what you learn in this series to building WPF desktop apps and Windows
Store apps. There will be differences, but there's a lot in common, too!

Lines 7 & 8 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 9 is doingwhen compiling the XAML code, ignore anything
prefixed with :d.

Ok, I know there are some questions left unanswered … 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. There are a few additional
attributes in lines 10 through 14 ... we may talk about them later in this series.

4. Understanding the relationship between the .xaml and .xaml.cs files
In Visual Studio’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
.cs version of the file, you’ll see that it defines a MainPage class, and furthermore, it
defines it as a PARTIAL class:



The other half of the equation is defined in lines 1 & 2 of the MainPage.xaml:

<phone:PhoneApplicationPage
x:Class="SoundBoard.MainPage"
...

While it doesn't use the term Partial like it's procedural counterpart, it does indicated 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 MediaElement class called
_audioPlayer in XAML and then call its methods or set its properties in C#. We’ll see
more examples of this later in this lesson.

5. 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:

<PhoneApplicationPage>
<Grid ...>
<Grid ... >
<MediaElement ... />
<Button ... />
</Grid>
</Grid>
</PhoneApplicationPage>

Here PhoneApplicationPage "contains" a Grid and the Grid "contains" a MediaElement
and Button. Or, perhaps more correctly in XAML parlance, UserControl's Content
property is set to Grid, and Grid's Children collection includes the MediaElement and
Button. 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:

<Button Content="Hello World" ... />

... or this ...

<Button ... >
Hello World
</Button>

since the Content property is the default property of the Button class.

6. 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 = newSolidColorBrush(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 properties 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.  Select the Brush property to reveal the Brush editor. 
2.  Make sure that Background is selected. 
3.  Select the Linear Brush tab (middle tab). 
4.  Move the selector all the way to the upper-right hand side of the color editor. 

I should now see the following in the Phone Preview pane:


... 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 ... >
<Button.Background>
...
</Button.Background>
</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 8 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:

<Button.Background>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">  
<LinearGradientBrush.GradientStops>
<GradientStopCollection>
<GradientStop Color="Red" Offset="1" />
<GradientStop Color="Black" Offset="0" />
</GradientStopCollection>
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
</Button.Background>
Notice how the <LinearGradientBrush.GradientStops> and <GradientStopCollection>
elements are 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 codeas long as it has enough information to create the object graph
correctly.

Recap
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 it's 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
PhoneApplicationPage 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 that 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.

No comments:

Post a Comment