Appendix A. XAML, the Extensible Application Markup Language

What’s XAML? XAML is Microsoft’s XML-based markup language for building stunning user interfaces. XAML was first introduced as part of the Windows Presentation Foundation, which Microsoft included as part of version 3.0 of the .NET Framework as a replacement for the two-decades-old graphics device interface (GDI)-based technology. XAML excels as a user interface markup language, separating the user interface design from the code-behind implementing an application’s business logic. XAML not only defines WPF and Silverlight UIs, but is also one of the options when building Windows Runtime applications for the Windows 8 operating system. If you’re coming from a web development background, you can think of XAML as similar to HTML, which you use to create UIs for your web pages. XAML is an XML document that represents the hierarchical structure of an application’s user interface.

This appendix serves as a quick introduction to XAML. We cover basic UI layout and the available UI controls, and then move on to an introduction to the data-binding features built into XAML. We wrap up by using DataTemplates to create a user interface for a domain model object.

Let’s start by examining the default XAML generated when you create a new application with the Windows Phone App project template. Figure A.1 shows the application generated by the project template.

Figure A.1. The default application

The default application generates a page that contains a Grid layout control, a StackPanel layout control, and two TextBlocks. The XAML markup for the form is shown in the following listing. We’ll refer back to this listing several times in the next few pages.

Listing A.1. XAML generated by the Windows Phone Application project template

The root of the XAML document is an element of type PhoneApplicationPage . Elements in a XAML document must be matched with a class name from either the .NET class libraries or the application’s code. The root element also contains a Class attribute that declares the full name of the C# class containing the code-behind for the user interface. The class named in the Class attribute must be derived from the class used as the root element. In this listing, the class MainPage is derived from the class PhoneApplicationPage.

You may have noticed that the root element uses the XML namespace phone. In XAML, namespaces can be declared with an assembly name or with a URI. An example of the URI version can be seen in the third line of the listing, declaring the x namespace. The fourth line of the listing shows the assembly name version declaring the phone namespace. We added the fifth line to the generated XAML; it’s a declaration for the Primer namespace, which is part of the application and doesn’t need to specify an assembly name.

Most XAML documents you create for Windows Phone will derive from either Phone-ApplicationPage or UserControl. Both PhoneApplicationPage and User-Control expect to have a single child control. In most cases the child control will be a layout control derived from the Panel class.

A.1. Layout controls

Layout controls are containers of other controls and are responsible for automatically positioning their children on the screen. The Windows Phone SDK includes three different layout controls named StackPanel, Grid, and Canvas.

The StackPanel control lays out its children in a horizontal or vertical stack, depending on the value of its Orientation property. The StackPanel in listing A.1 specifies an orientation of Vertical, which is the default value if an Orientation attribute isn’t declared. A vertical StackPanel stacks controls one on top of the other and ensures that all child controls have exactly the same width. A horizontal StackPanel stacks controls side by side and ensures that all controls have exactly the same height.

The Grid control lays out its children in a series of rows and columns. By default, a Grid has only one row and one column. Additional rows and columns are specified with the Grid.RowDefinitions and Grid.ColumnDefinitions properties, respectively. The Grid control called LayoutRoot in listing A.1 has two rows and a single column. The first row is given a height of Auto and uses as much height as needed. The second row is given a height of *, which tells the Grid to give the row a height that fills all of the remaining space. Child controls specify their rows and columns with the zero-based Grid.Row and Grid.Column attributes. For example, the Grid named ContentPanel specifies that it should be placed in the second row. Row and column indexes are zero-based. A control can span multiple rows and columns using the Grid.RowSpan and Grid.ColumnSpan attributes. If a child control doesn’t specify its row and column values, it’s placed in the first row and first column.

The Canvas control lays out its children using absolute positioning. The positions of child elements are declared using Canvas.Left and Canvas.Top properties. If a child doesn’t declare its position, it’s placed at coordinate (0,0).

A.2. Interacting with XAML controls

XAML for Windows Phone contains many of the common controls you’d expect in a user interface library. You should be aware that some of the controls present in WPF and Silverlight for the browser aren’t supported on Windows Phone. Check the MSDN documentation for a full list of controls supported by Windows Phone, found at http://mng.bz/tl47.

Let’s look at how to declare a simple form with a few controls and how to interact with the controls from code. The form will contain a TextBlock to display a label, a TextBox to receive input from the user, and a Button:

<StackPanel>
    <TextBlock Text="Please enter your name" />
    <TextBox x:Name="nameTextBox" />
    <Button Content="Save" Width="150" Click="Button_Click" />
</StackPanel>

You’ve given the TextBox a name using the x:Name attribute. The compiler will automatically generate a field for named controls, allowing you to easily access the control from code-behind. The Button control is defined with a Width value of 150 pixels. When the button is tapped by the user, a Click event is raised, and a custom event handler method named Button_Click is called:

private void Button_Click(object sender, RoutedEventArgs e)
{
    string name = nameTextBox.Text;
    MessageBox.Show("You entered : " + name);
}

In the Button_Click method, the generated field nameTextBox is used to retrieve the text entered by the user. The MessageBox class’s Show method displays a message to the user with a popup window.

A.3. Styles and resources

Specifying individual properties for every control can become onerous and error-prone. Suppose a form contains five buttons, and each button specifies a width of 150 pixels. If you want to change the width from 150 pixels to 155 pixels, you must make the change five times. Styles allow you to set properties on multiple controls at the same time. Styles are declared inside the Resources property of a XAML element. The following snippet declares a Style with the key NarrowButton that applies to Button controls:

<Grid.Resources>
    <Style x:Key="NarrowButton" TargetType="Button">
        <Setter Property="Width" Value="150" />
    </Style>
</Grid.Resources>

The NarrowButton Style will set a Button’s Width property to 150 pixels. Styles are explicitly set on controls using the StaticResource markup extension:

<Button Content="Save" Click="Button_Click"
    Style="{StaticResource NarrowButton}" />

Back in listing A.1, you can see two other examples of setting a Style with the Static-Resource markup extension. The Styles named PhoneTextNormalStyle and PhoneTextTitle1Style are two of a number of different styles provided by the Windows Phone SDK to allow you easily build applications that match the operating system’s look and feel. You can read more about built-in styles in chapter 2.

Styles can also be automatically applied to a set of controls. These automatic styles, called implicit styles, are activated by creating a style without a key.

A.4. Binding controls to model objects

One of the more powerful aspects of XAML is its ability to separate user interface markup from code logic. Data binding is one of the underlying features that enable UI separation. In the Button_Click method discussed earlier, the code-behind needs to know that a TextBox control named nameTextBlock exists in the UI markup. This knowledge links the UI markup to code-behind. If the TextBox is renamed, or if another type of control is used instead of a TextBox, the code will have to change as well.

Data binding enables you to write code-behind that’s unaware of the names and types of input controls used in the user interface. Let’s say there’s a C# domain model object with a UserName property:

public class SampleModel
{
    public string UserName { get; set; }
}

In the page constructor, a new instance of the model object is constructed and assigned to the page’s DataContext property:

DataContext = new SampleModel();

The DataContext property is used by the binding system as the data source when resolving data binding requests made in XAML markup. A data binding request is declared with the Binding markup extension:

<TextBox x:Name="nameTextBox" Text="{Binding UserName, Mode=TwoWay}" />

In this snippet, the markup declares that the TextBox should get its value from a property named UserName that exists on the model object referenced by the DataContext. Setting the binding Mode to TwoWay tells the TextBox to write any changes back to the UserName property as well. Now the Button_Click method can be updated by replacing knowledge of the TextBox with code that uses the DataContext:

private void Button_Click(object sender, RoutedEventArgs e)
{
    SampleModel model = (SampleModel)DataContext;
    MessageBox.Show("You entered : " + model.UserName);
}

Using plain C# objects works well if data binding is only writing to the model object. If portions of your user interface read from the model object as well, you can help out the data-binding system by implementing property change notifications.

A.5. Property change notifications

When a model object is used as a binding source, the binding system checks whether the model object implements the INotifyPropertyChanged interface. The INotifyPropertyChanged interface declares a single member—an event called Property-Changed. The binding system subscribes to the PropertyChanged event and tells the user interface controls to update the values they’re displaying when the event is raised. A sample model object that implements INotifyPropertyChanged is shown in the following listing.

Listing A.2. Implementing INotifyPropertyChanged

To implement INotifyPropertyChanged, an event called PropertyChanged is added to the class. The event should be raised whenever a property is changed. Inside the property setter, the code determines whether any listeners are subscribed to the event by checking whether the PropertyChanged event is null. If the event isn’t null, the event is raised and sent a new instance of the PropertyChangedEventArgs class . The name of the changed property is specified when constructing the event args.

In addition to binding user interface controls to model objects, the data-binding system also supports binding the property of one control to the property of another control. Binding one control to another is called element-to-element binding.

A.6. Element-to-element binding

When designing user interfaces, you’ll often come across usability features that have little to do with the business logic implemented in a model object. For example, a button might be disabled or hidden if the value in a TextBox is empty. The model object shouldn’t care whether a button is enabled.

Let’s see how to use element-to-element binding to echo the value entered into a TextBox in another control, in this case a TextBlock:

<TextBlock Text="{Binding Text, ElementName=nameTextBox,
    StringFormat='You entered: {0}'}" />

The Binding markup extension binds the Text property of the TextBlock to the Text property of a TextBox. The ElementName attribute identifies which TextBox to use—in this example, the TextBox called nameTextBox. Finally, the StringFormat markup extension is used so that the value isn’t merely echoed in the TextBlock but is a formatted message.

Let’s return to the example of disabling a Button when a TextBox is empty. There’s no automatic way to bind a Button’s Boolean IsEnabled property to the length of the TextBox’s Text string. You need a way to convert data during data binding.

A.7. Converting data during data binding

Data binding connects the property in a source object with a property in a target object. Sometimes the source property’s type doesn’t match the target property’s type. XAML’s data-binding system knows how to automatically convert certain types of data. For example, the data-binding system will automatically convert the string entered in a TextBox to an integer property in a bound object. XAML provides a mechanism called value converters as a way to convert data types that can’t be automatically converted.

At the heart of the value conversion process is the IValueConverter interface, which is found in the System.Windows.Data namespace. IValueConverter defines two methods: Convert and ConvertBack. The Convert method is called when copying the source property into the target property. The ConvertBack method is used in TwoWay binding when the target property’s value is copied back to the source property. A sample value converter, called StringLengthToBooleanConverter, transforms a string into a Boolean value, based on the length of the string. If the string is empty, the converter returns false:

using System.Globalization;
public object Convert(object value, Type targetType,
    object parameter, CultureInfo culture)
{
    string text = value as string;
    return string.IsNullOrEmpty(text) ? false : true;
}

To use a value converter in a XAML document, first declare an instance of the converter as a resource:

<Grid.Resources>
    <primer:StringLengthToBooleanConverter x:Key="stringLengthConverter" />
...
</Grid.Resources>

Value converters are specified using the Converter attribute of the Binding markup extension:

<Button Content="Save" Click="Button_Click"
    Style="{StaticResource NarrowButton}"
    IsEnabled="{Binding Text, ElementName=nameTextBox,
     Converter={StaticResource stringLengthConverter}}" />

We’ve scratched the surface of the features built in to the data-binding system and shown how to use data binding to separate user interface code from business logic. DataTemplates are another feature of XAML that enables the designer/developer workflow.

A.8. Using templates to build data model UI

DataTemplates allow application code to manage domain model objects without regard for the user interface used to display them. LongListSelectors, Content-Controls, and other content-based controls are designed to display generic objects. By default, a content-based control will call the ToString method of its contained object and display the result in the user interface. The default presentation can be replaced using a DataTemplate. The following listing shows how to create a DataTemplate for a ContentControl bound to a sample model object.

Listing A.3. Creating a DataTemplate for a ContentControl

Note that the ContentControl’s Content is using an empty Binding expression. An empty Binding expression causes the template to use the current binding context, which in this case is the page’s DataContext. The ContentTemplate property of the ContentControl is set by declaring a DataTemplate. The DataTemplate uses nested StackPanels to display a triangle, a label, and the value of the model’s UserName property .

Although we haven’t covered them here, templates are also used to customize the look and feel of controls. A designer can use templates to completely change the way a Button, TextBox, or other Control-derived class appears in the user interface.

A.9. Summary

XAML is a powerful application-development platform, and we’ve merely scratched the surface in this appendix. It has built-in support for transforms, animations, commands, custom controls, and more. Many XAML developers have adopted the Model-View-ViewModel (MVVM) pattern that uses XAML’s features to further separate user interface code from business logic. You can read more about the MVVM pattern in appendix B.

There are plenty of good references for learning XAML:

  • Windows Store App Development by Pete Brown (Manning Publications, 2013)
  • Silverlight.net, a Microsoft portal with links to tools, tutorials, and forums
  • “Microsoft Domain-Specific Languages and XAML Specifications,” an MSDN page listing the published XAML specifications (see http://mng.bz/rede)
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.135.187.106