How to: Create User Interfaces Using XAML and Expression Blend

Applies to: Functional Programming

Authors: Tomas Petricek and Jon Skeet

Referenced Image

Get this book in Print, PDF, ePub and Kindle at manning.com. Use code “MSDN37b” to save 37%.

Summary: This article shows how to use XAML in an F# Silverlight project and how to design the user interface using Expression Blend.

This topic contains the following sections.

  • Creating User Interfaces
  • Using XAML Files in F# Projects
  • Designing a User Interface Using Expression Blend
  • Summary
  • Additional Resources
  • See Also

This article is associated with Real World Functional Programming: With Examples in F# and C# by Tomas Petricek with Jon Skeet from Manning Publications (ISBN 9781933988924, copyright Manning Publications 2009, all rights reserved). No part of these chapters may be reproduced, stored in a retrieval system, or transmitted in any form or by any means—electronic, electrostatic, mechanical, photocopying, recording, or otherwise—without the prior written permission of the publisher, except in the case of brief quotations embodied in critical articles or reviews.

Creating User Interfaces

When creating Silverlight applications with rich user interfaces, the user interface can be separated from the application's functionality. This makes it possible to implement the functionality separately from the user-interface, which makes to code clearer and easier to maintain. Moreover, the user-interface description can be stored in a separate file (based on the XML format) that can be edited by user-interface designers independently from developers using tools such as Expression Blend.

This article demonstrates how to include user interface components specified in XAML in an F# Silverlight project. The F# integration with Visual Studio doesn't provide the same level of support for Silverlight development as C# or Visual Basic do, but using XAML as part of an F# project is still very easy. Figure 1 shows an F# application with a button designed using Microsoft Blend.

Figure 1. A Silverlight application created using F# and Expression Blend

Referenced Image

Using XAML Files in F# Projects

The first topic of this article is how to use XAML files from a standalone F# Silverlight project. The project can be created using the steps described in the first part of Tutorial: Creating a Silverlight Project in F# Using an Online Template. An alternative option is to create an F# Silverlight library and reference it from a C# Silverlight application. The steps for adding XAML files to the F# project are the same in both cases.

Adding XAML Files to the Project

A XAML file defines controls and other visual elements of the user interface. When using XAML as part of a Silverlight project, the file is stored as a resource of the compiled assembly. When the application starts, the runtime loads the XAML file from the resources and constructs the user interface elements.

In C# or Visual Basic projects, Visual Studio also generates a file containing members that provide statically-typed access to the named elements of the XAML file. This feature is not supported in F#, so the XAML file needs to be included as an ordinary resource (see How to: Access User Interface Elements Dynamically for an F# approach to access controls defined in the XAML file). The following steps describe how to add a XAML file to an F# project:

  1. Right-click on the project in the Solution Explorer and use the New Item command on the Add menu to add a new file named Sample.xaml. The content of the file will be discussed later. If there is no option for creating a XAML file, it is possible to use the XML or text file template and give the file the extension .xaml.

  2. Select the Sample.xaml file in the Solution Explorer, go to the Properties tool window, and change Build Action to Resource. This specifies that the file shouldn't be preprocessed (as usual in C# projects) but instead simply embedded to the assembly.

  3. Add a new F# source file named Sample.fs. This file will contain the F# type that loads the XAML content from the resources and implements the behavior of a control. The class definition that belongs to this file is shown below.

  4. After adding the file, the main application file (App.fs) can be changed to use this component. In this example, the name of the component is Sample and it will be located in the namespace UserInterfaceDemo.

At this point, the project should contain two additional files. The XAML file (Sample.xaml) will contain the user interface elements, and the F# source (Sample.fs) will load the user interface and add some functionality.

The following listing shows a simple XAML file that contains a button:

<UserControl Width="800" Height="600"
    xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml">
  <Grid>
    <Button Content="Click me!" x:Name="btn" />
  </Grid>
</UserControl>

When creating a XAML file with user interface components that can be loaded, the components typically use UserControl as the root element. The root element also includes xmlns specifications, specifying that the file is describing a XAML user interface. The main Button element is located inside a Grid element, which means that it will fill the entire area of the control. The user interface is improved later in this tutorial using Expression Blend. We also added an x:Name attribute to the Button. The name is used later to access the button from F# code.

As already mentioned, the F# code in Sample.fs will load the XAML file from the resources and create the user interface it describes. This can be easily done using the LoadComponent method provided by Silverlight:

namespace UserInterfaceDemo
open System
open System.Windows
open System.Windows.Controls

type Sample() as this =
    inherit UserControl()
    let loc = "/UserInterfaceDemo;component/Sample.xaml"
    let uri = new Uri(loc, UriKind.Relative)
    do Application.LoadComponent(this, uri)

The file defines a new type that represents the Silverlight control and inherits from the UserControl type. The constructor of the type loads the user interface using the XAML file from the resources. This is done using the Application.LoadComponent method. The method takes a URI that specifies the location of the XAML file in the resources. The path "/UserInterfaceDemo;component/Sample.xaml" consists of the name of the assembly, UserInterfaceDemo, and the name of the XAML file, Sample.xaml. Note that the LoadComponent method can locate the XAML file only when its Build Action is set to Resource.

Before running the application, make sure that the Sample control is loaded as the main visual element in the App.fs file. Then it should be possible to run the application, although without any interesting functionality.

Adding Event Handlers

F# does not automatically generate fields for accessing elements in the XAML file, so the elements need to be accessed by name. This tutorial uses a method named FindName, provided by Silverlight. The following snippet shows how to implement an event handler that changes the text of the button when it is clicked. The code can be added to the body of the Sample class (following the LoadComponent call):

let btn = this.FindName("btn") :?> Button
do btn.Click.Add(fun _ -> 
      btn.Content <- "Hello from F#!")

The snippet obtains a reference to the button using FindName. The method returns a value of the obj type, so the result needs to be cast to Button. Once the component has a reference to the button, it can register a handler with the Click event.

It is also possible to use the dynamic access operator (?), which is discussed in How To: Access User Interface Elements Dynamically. Links to more information about implementing reactive user interfaces in F# can be found at the end of this article. The next section demonstrates how to use user interface design tools when working with F# Silverlight projects.

Designing a User Interface Using Expression Blend

The F# integration with Visual Studio offers only limited support for editing XAML files using a designer. It is possible to load and modify XAML files in the designer, but it is not possible to create event handlers by double-clicking on controls. However, user interaction can easily be set up using data binding or by explicitly registering event handlers in F# code.

A professional look for a Silverlight application can be created using Expression Blend, which is a tool that both developers and professional designers can use. To load an F# project in Blend, select Open Project/Solution… and select either a Visual Studio Solution file (.sln) or an F# project file (.fsproj). Figure 2 shows Blend after changing the look of the button from the previous section.

Figure 2. An F# project in Microsoft Expression Blend

Referenced Image

Explaining how to use Blend is beyond the scope of this article. The following steps provide a brief guide on how to create a button similar to the one in Figure 1. The steps describe how to edit the control template of a button and replace the default style with a rounded rectangle with a gradient fill.

Editing the Control Template of a Button

  1. Expression Blend uses the same solution and project files as Visual Studio, so the first step is to open the solution created in the previous section and open the Sample.xaml file.

  2. Right-click on the button, select Edit Template and choose Create Empty… This creates a new template for specifying the look of buttons. The template can be applied to other buttons in the application.

  3. Select the Border control from the left toolbar and drop it onto the canvas. Align the border to fill the space of the template using the Selection tool. This automatically binds the border size to the size of the button.

  4. To create a rounded rectangle, specify the value of CornerRadius in the Appearance tab in the right panel. The gradient fill and the border color can be specified in the "Brushes" tab.

  5. The content of the button (such as a text label) can be displayed by creating a special placeholder. To do this, select ContentPresenter from the left toolbar and add it to the control template. In the Layout tab on the right, set the vertical and horizontal alignment of the content to align the content to the center.

When the XAML file is changed using Blend, the application can be started immediately using F5. After saving the changes, the project can be also reopened in Visual Studio to view the changes made in the XAML file. After completing the steps above, the Sample.xaml file should contain a new ControlTemplate element located inside a UserControl.Resources element. This UserControl.Resources element contains nonvisual elements that are referenced from other places in the XAML file. The control template created in Expression Blend in Figure 2 looks as follows:

<ControlTemplate x:Key="GreenBtn" TargetType="Button">
  <Grid><Border BorderBrush="#FF131C3F" BorderThickness="5"                  CornerRadius="10">
    <Border.Background>
      <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
        <GradientStop Color="#FF637B91" Offset="0"/>
        <GradientStop Color="#FF2D3668" Offset="1"/>
      </LinearGradientBrush>
    </Border.Background>
    <ContentPresenter />
  </Border></Grid>
</ControlTemplate>

The elements nested inside ControlTemplate specify the user interface elements that should be rendered in place of the button. The x:Key attribute specifies the name of the template that is used later to apply the template to a button. In Microsoft Blend, this key is specified when naming a newly created template. The TargetType property specifies that the template can be applied only to button elements. The tag that creates the button is modified to use the template as follows:

<Button Content="Click me!" x:Name="btn" Margin="229,209,315,270"         Template="{StaticResource GreenBtn}" FontSize="26.667" />

The Template attribute creates a reference to a template using the StaticResource markup extension. The extension specifies that the value of the property should be set to the object that is stored in the page resources with the GreenBtn key.

Summary

This article looked at how to use XAML to create user interface in an F# Silverlight application. It started with a template that creates an empty project containing just F# code. The next step was to add a XAML file as a "Resource" to the project and to create a type representing the user control that loads the XAML content when it is created.

The sample also demonstrated how to write a simple handler for the Click event of a button to demonstrate the basic approach. Links to more advanced techniques are provided below. Finally, the last part of the article demonstrated how to use Microsoft® Expression Blend® to design the user interface of an F# application.

Additional Resources

The following article discusses a better way of accessing controls than using the FindName method and alternative ways of handling events:

This article discusses only the specific aspects of user interface development. For more complete guides that create complete applications or components, see the following tutorials:

To download the code snippets shown in this article, go to https://code.msdn.microsoft.com/Chapter-3-Reactive-Client-8a458f7d

See Also

This article is based on Real World Functional Programming: With Examples in F# and C#. Book chapters related to the content of this article are:

  • Book Chapter 9: “Turning values into F# object types with members” explains how to use object-oriented features of the F# language. This is an important topic for client-side development because it explains how to mix the object-oriented Silverlight design with the functional programming style.

  • Book Chapter 16: “Developing reactive functional programs” discusses how to write reactive user interfaces using asynchronous workflows and events. It also includes a basic introduction to the Reactive Framework (Rx).

The following MSDN documents are related to the topic of this article:

Previous article: How to: Design Silverlight User Interfaces

Next article: How to: Access User Interface Elements Dynamically