WPF Part 3 - The basic concepts of XAML

After I've learned much about the possibilities XAML and the WPF can give us developers, I would like to review the basic concepts of XAML. As I mentioned in the last article and as you'll see at first glance, XAML is based on XML. This means that every XAML file has a root element that includes all other elements. Furthermore all elements must be nested correctly. The following example shows the correct...

  1. <StackPanel>
  2.   <TextBlock>
  3.     [...]
  4.   </TextBlock>
  5. </StackPanel>

...and the incorrect way:

  1. <StackPanel>
  2.   <TextBlock>
  3.     [...]
  4. </StackPanel>
  5.   </TextBlock>

If you develop a window or a navigation application, the root element is a Window or a Page element. If you want to describe a resource or an application file, you would use a ResourceDictionary or an Application element. You could theoretically use a TextBox, a Button or any WPF element for the root, but this wouldn't make sense in most scenarios.

As in XML, you must write the values of attributes surrounded by quotation marks, e.g. <TextBox Width="150">. Though XAML is using the XML syntax, the characteristic XML-prolog is not necessary (as a reminder: <?xml version="1.0" ... ?>).

XAML-Mapping:
There are namespaces, elements and attributes in a WPF file. These constituent parts have special meanings:

  • The elements comply every time with a WPF class. If you use a <TextBox> e.g., there will be a TextBox instance, created trough the default constructor of that class.
  • The attributes of an element are mapped to the properties or events of the newly created object. This properties must be public and value types. For all other types there must be a typeconverter available. There are different typeconverters already available in the WPF.

Names:
All components inherit the property "Name" from the class "FrameworkElement". This property defines an unambiguous name for all elements. You can use this name like a normal variable to access an element, defined in the XAML file. If you have a TextBox element defined like this: <TextBox Name="textBox1" Text="This is an example!" />, you can access the element in C# in this way: this.textBox1.Name.

Attribute-Syntax:
To set the properties of an element defined in the XAML part, you write the properties in the known XML attribute syntax. If you want to set the width and the text of an TextBox element, you can write something like this: <TextBox Width="150" Text="Hallo" />.
This notation is very short, but has one big disadvantage. Because you can only set strings, you have not much possibilities to set the available attributes. If the assignment is more complex, you can use the following syntax.

Property-Element-Syntax:
With this syntax you can set attributes in a more complex way. The syntax uses a combination of the element name, a dot, and the name of the property you want to set, for example <TextBox.Background>. The following example shows a TextBox element, with a complex background:

  1. <TextBox Text="colored">
  2.   <TextBox.Background>
  3.     <LinearGradientBrush>
  4.       <GradientStop Color="White" Offset="0.0" />
  5.       <GradientStop Color="Blue" Offset="1.0" />
  6.     </LinearGradientBrush>
  7.   </TextBox.Background>
  8. </TextBox>

Namespaces:
In order to access special types within the WPF or to use special XAML keywords, there are XML namespaces in the root element of every XAML file. The following namespace is the default namespace and provides most of the WPF types:

xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

As you can see, there is no prefix declaration. This is the reason, why you can access e.g. a <TextBox> element without a prefix. If we would write something like this, the namespace gets a prefix:

xmlns:default="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

As from now, you must write <default:TextBox>, to access the WPF TextBox element. This isn't common and would cause to a circumstantial syntax.
The second namespace in a normal XAML file defines the mapping for the XAML markup. This namespace has the default prefix "x":

xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

Beside the two predefined namespaces, you could also add other CLR namespaces. This could be an own or an existing CLR namespace. To define an additional namespace, you must use a prefix for it, because there is already one namespace (the default one) without a prefix. The following example shows the syntax, which has to be used to add a new namespace:

xmlns:clr="clr-namespace:System;assembly=mscorlib"

The first import note is the prefix, in this example "clr". The prefix is defined after a colon. I will use "clr" in all my future code snippets and solutions. The second import note is the name of the new namespace, which is introduced with "clr-namespace". After that, you must specify the name of the namespace. In this example, I used "System". The third and last note is the assembly, in which the namespace is defined. You specify the name of the assembly without a path and the extension, introduced with the keyword "assembly". In this example I used "assembly=mscorlib".

Information: Is the namespace located in the same assembly, you can omit the assembly name.

I've created a Visual Studio 2008 solution, which you can download here. This solution contains an example, where you can see the usage of own namespace declarations. Please have a look at the XAML code for the window:

XAML Sourcecode Namespace Example (Window) (17 lines, approx. 1,00 KBytes)

In this source you can see the two namespace declarations, which introduced the prefixes "prjMultiplier" and "prjDivider". In the first declaration, I must specify the assembly, because the C# class "Multiplier" is in another assembly. The class "Divider" is in the same assembly as the XAML code for the window, so I could omit the assembly name.

After I defined this namespaces, I could use the statement <prjMultiplier:Multiplier Multiplicand="5" Multiple="10" /> instead of a fix label text for the first example, and the statement <prjDivider:Divider Dividend="100" Divisor="2" /> instead of a fix label text for the second example. At runtime, the classes "Multiplier" and "Dividend" will be instantiated, the properties will be set and the results are returned to the XAML code.

The example application.
The example application.
Here you can see a screenshot of the application. The two results are calculated through the custom classes.
I hope you've learned somewhat about the basic concepts of XAML. In the next part, I will give a closer look at XAML.

Author: Fabian
Date: Tuesday, 22. January 2008 21:18
Trackback: Trackback-URL Category: WPF

Feed: RSS 2.0

Leave a Reply