How to: Access User Interface Elements Dynamically
Applies to: Functional Programming
Published: January 2010
Summary: This article shows how to implement the F# dynamic operator (?) to make it possible to easily access user interface elements created in XAML.
This topic contains the following sections.
- Creating User Interfaces
- Implementing the Dynamic Operator
- Using the Dynamic Operator in Practice
- 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.
When embedding XAML definitions into an F# Silverlight project, the Visual Studio integration with F# doesn't automatically generate fields for accessing user interface elements. A standard way to access such controls is to use the FindName method that takes string as an argument. This suggests an implementation of the F# dynamic operator (?), which enables accessing a button named SubmitBtn just by writing this?SubmitBtn.
After looking at the operator implementation, the article demonstrates how to use the operator using a sample application that allows users to enter text. After clicking on the "OK" button, the application displays a "Hello world!" message, as shown in Figure 1.
To keep this article simple, the details of creating a new Silverlight project in F# are omitted. This information can be found in the article Tutorial: Creating a Silverlight Project in F# Using the Online Templates. However, the approach discussed in the next section will work for any type of Silverlight (or even WPF) project created in F#.
The dynamic operator (?) makes it possible to use member access syntax to invoke members that are not known at compile time. If foo is some object that supports the operator, the compiler allows writing foo?Bar even if it cannot verify that the Bar member exists. Behind the scenes, the call is translated to a call to the (?) operator with the name of the member as an additional argument.
The operator takes two parameters. The first one is the target object and the second one is the name of the member. The following snippet can be added to a Silverlight project as a separate file (e.g., Utils.fs). It is also possible to include the let declaration inside the types that implement the individual pages because the code is very simple:
module FSharp.Silverlight open System.Windows.Controls let (?) (arg:Control) name : 'R = arg.FindName(name) :?> 'R
When accessing user interface elements, the target object needs to be of type Control. This allows the snippet to locate the element using the FindName method. An interesting aspect of the implementation is that the operator is generic. When using the operator, the caller specifies the type of the result and the operator automatically casts the element to this type. If the wrong type is specified, the conversion may fail (at runtime) because the access is dynamically typed. The benefit of making the operator generic is that F#'s type inference simplifies code that uses the operator. For example, a typical pattern looks as follows:
The snippet declares a new value btn. The expression assigned to the value uses the dynamic operator to get an element named SubmitButton. Because the type is specified in the type annotation on btn, the result of the dynamic lookup does not need to be cast to Button. F# infers that the type argument for the dynamic operator is Button and automatically inserts the cast. The next section shows a larger example that demonstrates the functionality.
The user interface displayed in Figure 1 can be created by adding a XAML file that defines the layout of a control with a text box, a button, and a text element for displaying a message. For more information on using XAML files in F# see How to: Create User Interfaces Using XAML and Expression Blend. The content of the XAML file looks as follows:
<UserControl xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Width="800" Height="600"> <StackPanel Orientation="Vertical" Margin="40"> <StackPanel Orientation="Horizontal"> <TextBox Width="200" x:Name="InputBox" Margin="5" /> <Button Content="OK" Width="50" x:Name="SubmitButton" Margin="5" /> </StackPanel> <TextBlock Margin="10" FontSize="16" x:Name="OutputInfo" /> </StackPanel> </UserControl>
The file creates a simple layout that uses one StackPanel to create an input box with a button to its right. A second StackPanel places a TextBlock element below the first StackPanel. All elements that will be programmatically accessed later have an x:Name attribute that specifies the name of that control. The following snippet shows how to implement the application's logic in F# (assuming the name of the XAML file in resources is Hello.xaml).
namespace UserInterfaceDemo open System open System.Windows open System.Windows.Controls open FSharp.Silverlight type HelloControl() as this = inherit UserControl() let loc = "/UserInterfaceDemo;component/Hello.xaml" let uri = new Uri(loc, UriKind.Relative) do Application.LoadComponent(this, uri) let btn : Button = this?SubmitButton let inp : TextBox = this?InputBox let out : TextBlock = this?OutputInfo do btn.Click.Add(fun _ -> out.Text <- "Hello " + inp.Text)
The snippet starts by opening the key Silverlight namespaces together with the dynamic operator implementation from FSharp.Silverlight. Next, it defines a type to represent the user control with a constructor that loads the XAML file from a resource. After LoadComponent is called, the runtime creates all of the user interface elements.
The class contains three local fields that are initialized using the dynamic operator. The operator locates the button, input text box and output label in the collection of controls. The fields need type annotations because they are the only hints that tell the compiler what the types of the controls are. After getting references to all three controls, the snippet adds a simple event handler for the btn button. The handler reads the text from the input box and displays it with a "Hello" prefix using the output label.
This article demonstrated how to use the dynamic operator (?) in F# to get an easy way of accessing user interface elements. The implementation of the operator simply calls the FindName method, but it makes the syntax more convenient. Using this operator, controls can be accessed using the dynamic member access syntax this?SubmitButton. The use of the operator also benefits from F#'s type inference.
Working with the operator was demonstrated using an example that shows a common pattern for creating Silverlight user interfaces. A class contained a local field with a type annotation for each control and initialized it using the dynamic operator. This is a relatively easy way of manipulating Silverlight controls from F# code.
This article was built using a simple F# template and a XAML file to define the user interface of the application. More information about these two steps can be found in the following articles:
This article discusses only 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 http://code.msdn.microsoft.com/Chapter-3-Reactive-Client-8a458f7d
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:
F# Client-Side Application (Silverlight)—the F# project template used in this tutorial (at Visual Studio Gallery).
Operator Overloading (F#) contains a list of all F# operators that can be overloaded including the dynamic operator (?).
FrameworkElement.FindName Method provides more information on accessing XAML elements programmatically.
Previous article: How to: Create User Interfaces Using XAML and Expression Blend
Next article: Numerical Computing