How XAML works - Creating Objects With XAML
Tuesday, 17 March 2015
Article Index
How XAML works - Creating Objects With XAML
Properties

XAML can be confusing - especially if you think it is a markup language like HTML - it isn't. XAML is a general purpose object instantiation language and to find out what this means - read on. 

 

Banner

 

XAML is a, mostly declarative, object instantiation language – that is it’s a way of describing using XML what objects should be created and how they should be initialised before your program starts running.

If you keep this in mind then XAML is becomes a lot more transparent and easier to understand. 

Its use in conjunction with WPF is just one of its many possible applications and indeed it has started to appear in other places – Windows Workflow for example and of course it is the UI design language for Windows Store apps i.e. WinRT apps.

To explain exactly what XAML is this article works with custom classes that have nothing to do with WPF so that we can find out about XAML in a completely general context that will help you understand all of its uses potential and current.

Declaritive Instantiation

We could start with a non-WPF project to prove how general XAML is we but this would waste a lot of time adding references and “usings”.

So let’s start with a simple WPF Application using Visual Studio Community Edition say.

You don’t need to modify any of the generated code but you do need to add a simple custom class with which to try out XAML:

public class MyClass
{
 public MyClass()
 {
 }
}

All that is necessary for a class to be instantiable by XAML is that it has a parameterless constructor and it can’t be a nested class.

It can have other constructors but these play no part in its working with XAML. Notice that as structs have a default parameterless constructor provided automatically by the system you can instantiate structs in XAML.

Now that we have our minimal class we can write some XAML to create an instance of it. However first there has to be some way of making the link between the XAML document and the class definition.

This is achieved by importing the class’s namespace into XAML.

You can import the namespace of any assembly and use namespaces to indicate exactly which class you are referring to. In this case we need to import the namespace of the assembly that the XAML file is part of, i.e. the current project.

So moving to the XAML editor we need to add a single line to the <Window> tag: 

<Window x:Class="WpfApplication1.Window1"
xmlns="http://schemas.microsoft.com/
winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/
winfx/2006/xaml"
xmlns:m="clr-namespace:WpfApplication1"
Title="Window1" Height="300"
Width="300" Loaded="Window_Loaded">

The “clr-namespace” is a special token which is interpreted to mean “get the namespace from the named CLR runtime”.

In general you might also need an “assembly=” token to supply the location of the assembly but in this case it’s assumed to be the current project.

Following this any name prefixed by m: is taken from the namespace of the current project - which is assumed in this case to be WpfApplication1.

The next thing we have to do is to get rid of the <Grid> tags as we cannot nest a general class within a grid – it needs a class that can be displayed.

To create the instance of our class all we have to enter is:

 <m:MyClass>
 </m:MyClass>

between the <Window> and </Window> tag.

The project should now run without errors. If you do see any errors then it will be due to loss of synchronisation between namespaces – simply run the project again. The need to keep namespaces and other generated files in sync is one of the problems of splitting instantiation from the runtime.

XAML

Naming objects

So we have a working program that creates an instance of MyClass but this does us very little good as the instance is dynamic and goes out of scope as soon as the main form is loaded!

To keep the instance in scope, and to allow us to work with it within the C# code, we need to give the instance a name.

Standard WPF components are generally given a name via the NAME property but a more direct mechanism for custom classes is to use the facilities provided by the XAML “x” namespace. The “x:Name” attribute can be used to set the name used by XAML to create the instance:

<m:MyClass x:Name="MyObject1">
</m:MyClass>

With this change you can now run the program and, with the help of a breakpoint and the debugger, you can confirm that there it really does create MyObject1. Put a breakpoint in the MainWindow constructor after the call to InitializeComponent(). You will see MyObject1 listed in the Locals window:

 

MyObject

 

If you would like to see the generated C# code that does the instantiation then load the file called MainWindow.g.cs - click on the Show All files icon in the Solution Explorer:

solution

 

Navigate to the obj\Debug directory - where you will find MainWindow.g.cs.  

If you look at the code you will discover that what happens boils down to:

internal WpfApplication1.MyClass MyObject1;

followed a few lines later by:

System.Uri resourceLocater=new System.Uri(
 "/WpfApplication1;component/mainwindow.xaml",
 System.UriKind.Relative);
System.Windows.Application.LoadComponent(
                     this, resourceLocater);

This creates the objects defined in the XAML file and then the instruction:

this.MyObject1 =
        ((WpfApplication1.MyClass)(target));

makes the connection between the object and the variable referencing it.

As already mentioned, WPF classes inherit a Name property which can be used in place of x:Name. If a class doesn’t have a Name property then use x:Name.

To assign a name property to a class you simply use the RuntimeNameProperty Attribute to designate a property that will store the name of the instance. For example:

[RuntimeNameProperty("MyName")]
 public class MyClass
 {
  public MyClass(){}

  public string MyName
  {
   get { return _MyName; }
   set { _MyName= value; }
  }
private string _MyName= string.Empty;
}

However this only works if the class belongs to another assembly and not the one actively being edited in Visual Studio say.

Notice also that the XAML compiler will create an instance with the name you specify and store the name in the property in case you need to make use of it.

Initialising Properties

As with WPF objects in XAML we can set properties on custom objects. 

For example, if we add a trivial int property to MyClass:

public int MyProperty
{
 get{return m_MyProperty;}
 set{m_MyProperty=value;}

private int m_MyProperty;

we can set this to “20” within XAML using:

<m:MyClass x:Name="MyObject1" m:MyProperty="20">
</m:MyClass>

Now if you run the program and examine it after an early breakpoint you will see that the object has been created with the property set to 20.

You can also modify the property using the Property window:

properties

 

Notice that the property type implied by XAML is string but the conversion to int is automatically taken care of – essentially by XAML asking the Convert object to convert the string to the type of the property.

This is fine as long as Convert has definitions for the appropriate ToType.

In addition to converting to the usual primitives, XAML will also try to convert a string to a suitable value of an enumeration by performing string matching against its values.

 

Banner

<ASIN:0735619573>

<ASIN:0672330318>

<ASIN:0596526733>



Last Updated ( Tuesday, 17 March 2015 )
 
 

   
Banner
RSS feed of all content
I Programmer - full contents
Copyright © 2015 i-programmer.info. All Rights Reserved.
Joomla! is Free Software released under the GNU/GPL License.