CHAPTER 7
The previous chapter looked at creating custom graphics using F#. In this chapter, we’re going to look at how to create form-based applications in F#. There are a number of different technologies for creating form-based applications in .NET, including Windows Forms, WPF, Silverlight, and GTK#. Since each of these technologies is based on similar ideas, we'll stick to looking at one: WPF.
WPF allows you to define forms in two ways: first by manipulating the WPF objects directly, and second by defining forms in an XML dialect called XAML. XAML is useful because there are several different user interface design packages available that allow designers create rich user experiences in XAML. Designers can then pass these over to developers to wire them into the application. We’ll look at XAML later in the chapter; for now we’ll take a look at how to create forms using the WPF objects directly.
Using the objects directly is a good approach when you want to create a simple form that only consists of a few controls. In this case, the creation of the form is probably simple enough that it’s not worth the effort of using a designer. Also, creating forms in this way is a good learning experience because it helps you better understand how each of the control types fits together.
We want to create a form with three controls: a text box, a descriptive label in front of the text box, and a button immediately below it. To create our desired layout, we’re going to use two stack panels: a horizontal one to hold the label and the text box, and a vertical one to hold the horizontal stack panel and the button directly below it.
To create the application, we’re going to start a new F# project and add references to PresentationCore.dll, PresentationFramework.dll, System.XAML.dll (required even though we’re not using any XAML at this stage), and finally WindowsBase.dll. We’ll then need some open statements to provide easy access to the namespaces:
open System
open System.Windows
open System.Windows.Controls
We’re almost ready to create our controls, but first we need to tidy up one slightly annoying aspect of WPF. In WPF, there is a collection called UIElementCollection which is used to store child controls. This collection has an Add method which has both a side effect—adding the control to the collection—and a returned value—the index of the newly added control. We almost never have any interest in the index of the control, so we can ignore the return value; however, F# will give us a warning that we are ignoring a return value because this is often the indication of an error in functional programming. To work around this we need to add a short helper function to add the item to the control collection without returning the index. In WPF, not all controls can have collections of children; only controls that inherit from Panel have a Children collection. This is why we add a type constraint to the second parameter of the helper function shown in the following sample. The function will only accept controls that derive from Panel as its second parameter. The implementation of the addChild helper function is shown in the following code as well. It simply adds the given control to the Children collection and ignores the result.
// Adds a child to a panel control.
let addChild child (control: Panel) =
control.Children.Add child |> ignore
Now we can start creating our controls. We’re going to define a createForm function to handle creating the controls. There’s really no magic to it. We simply create the horizontal stack panel and then add a label and text box to it. Next we create the vertical stack panel and add the horizontal stack panel, followed by the vertical, followed by the button control, all while not forgetting to wire up the button's event handler.
// Function to create the form interface.
let createForm() =
// Horizontal stack panel to hold label and text box.
let spHorozontal =
new StackPanel(Orientation = Orientation.Horizontal)
// Add the label to the stack panel.
spHorozontal |> addChild (new Label(Content = "A field",
Width = 100.))
// Add a text box to the stack panel.
let text = new TextBox(Text = "<enter something>")
spHorozontal |> addChild text
// Create a second stack panel to hold our label
// and a text box with a button below it.
let spVert = new StackPanel()
spVert |> addChild spHorozontal
// Create the button and make it show the content
// of the text box when clicked.
let button = new Button(Content= "Press me!")
button.Click.Add(fun _ -> MessageBox.Show text.Text |> ignore)
spVert |> addChild button
// Return the outermost stack panel.
spVert
And that’s all there is to creating a form. To show the form, we need to host it in a window, and then create a WPF application to create an event loop and show the control. The code to do this is as follows:
// Create the window that will hold the controls.
let win = new Window(Content = createForm(),
Title = "A simple form",
Width = 300., Height = 150.)
// Create the application object and show the window.
let app = new Application()
[<STAThread>]
do app.Run win |> ignore
As we saw in the previous chapter, when starting in the WPF event loop we need to ensure the STAThread attribute is attached to the starting method call. On executing this application, we should see the following form:

Figure 6: WPF Form Created in F#
While the approach of creating the user interface yourself can work well for simple applications, if we want more complex styles and effects it’s often better to use XAML. In this example we’re going to look at creating a form with exactly the same layout and functionality as the previous form. The only thing that changes is the layout will now be defined in XAML and the behavior of the form will be defined using F#. The XAML definition of our form is the following:
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="A XAML Form" Height="350" Width="525">
<StackPanel>
<StackPanel Orientation="Horizontal">
<Label Width="100">A field</Label>
<TextBox x:Name="MessageTextBox"><enter something></TextBox>
</StackPanel>
<Button x:Name="PressMeButton">Press me!</Button>
</StackPanel>
</Window>
It’s fairly easy to see from the XAML definition that the layout consists of two stack panels, a label, a text box, and a button as before. We’ve given names to the text box and button as these are the objects we’ll need to access from code. The text box is called MessageTextBox and the button is called PressMeButton. F# has slightly less integration with XAML than C#, so we need to define a couple of helper functions to help us load the XAML and access the controls defined within in it. In a small example like this, the extra code required for these helpers can seem like a lot of overhead, but in a more realistically sized application the cost of these extra functions will quickly be amortized as the helper functions are reused throughout the application.
The XAML definition we’ve just seen will need to be added to the F# project as MainWindow.xaml. In the properties window for this file you’ll need to set the build action to EmbeddedResource so that it will be embedded into the assembly manifest as a resource stream. That’s pretty much all we need to do for the XAML part.
Before we start on the F# part, we’ll need to reference the same assemblies as the previous application (PresentationCore.dll, PresentationFramework.dll, System.XAML.dll, and SystemXML.dll) and we’ll need the following open statements.
open System
open System.Reflection
open System.Windows
open System.Windows.Markup
open System.Windows.Controls
We need two helper functions: a function to load the XAML window, and an operator to help us access the controls that are defined within the window. The first function is straightforward. To get access to a manifest resource stream we need access to the assembly object that contains the resource. In this case, as our helper function is defined in the same assembly that the resource will be embedded in, we can use Assembly.GetExecutingAssembly()to get a reference to the assembly object. If the helper function was not in the same assembly as the resource file, for example, it might have been moved into another assembly so it could be shared between projects more easily. We would need to pass the assembly object to the function as a parameter. Once we have the resource stream we can load it using the XAMLReader class that is part of the WPF framework. This is what our function looks like:
// Load a XAML file from the current assembly.
let loadWindowFromResources name =
let currentAssem = Assembly.GetExecutingAssembly()
use xamlStream = currentAssem.GetManifestResourceStream(name)
// Resource stream will be null if not found.
if xamlStream = null then
failwithf "The resouce stream '%s' was not found" name
XamlReader.Load(xamlStream) :?> Window
There are a few points worth noting about the function. First, we use the use keyword instead of let to create the binding to our xamlStream identifier that represents the resource stream. The use keyword is equivalent to using in C#, and means that the stream will have its Dispose method called as soon as it drops out of scope. Secondly, we make a null check on the xamlStream identifier and raise an exception if the value is null. This is because the method GetManifestResourceStream returns null if no resource stream matching that name is found, and by raising an exception in this case we’ll get a more meaningful exception. Finally, we load the XAML file using the XAMLReader.Load method. This method returns an object so we need to cast to the actual type of the object that we are expecting, which in this case is the Window class. We could easily have chosen to load the XAML from a file on the disk rather than a file embedded in the manifest; the advantage of using a file in the manifest is that we can be sure that it is distributed with the assembly.
The second function we need to define is a way to access the controls that are positioned within the window. The base class FrameworkElement, which Window inherits from, provides a FindName method to find our named controls. One possibility would be to use this method directly to find the controls we’re interested in:
let pressMeButton = win.FindName("PressMeButton") :?> Button
While this is a perfectly acceptable way to do this, F# provides a fun alternative which can save you a little typing. F# lets you define a custom dynamic operator, which behaves in a similar way to the dynamic keyword in C#. The dynamic operator is a question mark (?) and it allows you to make what looks like a method or property call, but recover the method or property name as a string so that you can do a dynamic lookup. Here is how we would define our dynamic operator:
// Dynamic lookup operator for controls.
let (?) (c:obj) (s:string) =
match c with
| :? FrameworkElement as c -> c.FindName(s) :?> 'T
| _ -> failwith "dynamic lookup failed"
Here we see a custom operator followed by two parameters: the first of type object and the second of type string. The first object is the object we’re dynamically invoking, and the second is the name of the property or method being called. The implementation of the operator pattern matches against the object to check if it is of type FrameworkElement. If it isn't, we throw an exception. If it is, we call the framework element’s FindName method. Don’t worry if that isn't 100% clear at the moment; the dynamic custom operator is one of the more advanced features of F#. The thing to retain is that defining this operator now lets you do a dynamic lookup on the window, which could be used to find the button we are interested in using:
let pressMeButton: Button = win?PressMeButton
Now that we have those two helper functions in place, we’re ready to create our XAML-based window. To do this we’ll implement a function, createMainWindow, which will be responsible for creating the window and wiring up events to the relevant controls.
// Creates our main window and hooks up the events.
let createMainWindow() =
// Load the window from the resource file.
let win = loadWindowFromResources "MainWindow.xaml"
// Find the relevant controls in the window.
let pressMeButton: Button = win?PressMeButton
let messageTextBox: TextBox = win?MessageTextBox
// Wire up an event handler.
let onClick() =
MessageBox.Show(messageTextBox.Text) |> ignore
pressMeButton.Click.Add(fun _ -> onClick())
// Return the newly created window.
win
// Create the window.
let win = createMainWindow()
// Create the application object and show the window.
let app = new Application()
[<STAThread>]
do app.Run win |> ignore
The implementation of createMainWindow is quite straightforward. We load the window itself using the helper function loadWindowFromResource. Once we have the window, we grab references to two of the controls that it contains: the button, pressMeButton, and the text box, messageTextBox. Once we have these references it’s easy to add an event handler to the button’s click event and get access to the text box’s Text property from this event handler. To complete our function, it’s just a matter of returning our newly created window.
To show the window, we just have to call the createMainWindow function and then start the WPF event loop to show the window, just as we have done in the previous examples. The window will look exactly as it did in the previous example, but now that the layout of the window is defined in XAML it is easy to add some more styles so the controls won't look as plain.
A common way of implementing forms in WPF is to use the MVVM design pattern. For those of you who may be unfamiliar with MVVM, let’s do a quick recap of what this design pattern is. MVVM stands for Model-View-ViewModel. In this design pattern, the Model is the objects that represent the data or domain. The View is the user interface—in this case we’ll be using XAML, but we could use WPF objects directly if we so choose. The ViewModel is the layer of objects that sits between the View and the Model to provide the mapping between them and to react to events and changes within the GUI. The View communicates with the ViewModel through WPF’s powerful data binding mechanism.
We’ll take a look at implementing a simple form in the MVVM style. MVVM is a large topic and this example isn’t designed to show all the techniques involved in implementing the MVVM design pattern. Instead, it aims to give you a taste of doing MVVM in F# and to allow you to apply your existing MVVM knowledge, or information from other MVVM articles, to an F# MVVM implementation. The example we’re going to look at is how to implement a simple master detail page in the MVVM style. The application we're constructing will be for viewing our stock of robots. We’ll be presented with a list of robots and allowed to click on a robot to see more details about it.
As we’ve already said, MVVM separates code into three different components: the model, the view, and the ViewModel. In addition to this, we’ll add a “repository” which will abstract the data access logic. We’ll go through the parts of the application in the following order: we’ll look at the model and repository, then the ViewModel, and finally the view.
Because our application is a simple read-only view of some data, there is no domain logic. This means the model part of the application is very simple—only a data container is required. For the data container we’ll use an F# record type:
type Robot =
{ Name: string
Movement: string
Weapon: string }
As you can see, we’re only going to store three pieces of information about our robot: its name, how it moves, and its weapon. Our application is so simple that this is all we need for the model. For the sake of simplicity we’re going to hard code the data in our repository, but in a more realistic example this would come from a database.
type RobotsRepository() =
member x.GetAll() =
seq{ yield {Name = "Kryten"
Movement = "2 Legs"
Weapon = "None" }
yield {Name = "R2-D2"
Movement = "3 Legs with wheels"
Weapon = "Electric sparks" }
yield {Name = "Johnny 5"
Movement = "Caterpillars"
Weapon = "Laser beam" }
yield {Name = "Turminder Xuss"
Movement = "Fields"
Weapon = "Knife missiles" }
}
Now that we have our model and repository, we’re ready to look at the ViewModel. One of the main purposes of the ViewModel is to provide the view with some properties that it can data bind to. This means that the ViewModel class is made up of a number of small methods and properties that interact with each other, so I think it would be helpful for me to show you the whole ViewModel and then discuss the individual parts that comprise it.
type RobotsViewModel(robotsRepository: RobotsRepository) =
// Backing field of the on property change event.
let propertyChangedEvent =
new DelegateEvent<PropertyChangedEventHandler>()
// Our collection of robots.
let robots =
let allRobots = robotsRepository.GetAll()
new ObservableCollection<Robot>(allRobots)
// The currently selected robot
// initialized to an empty robot.
let mutable selectedRobot =
{Name=""; Movement=""; Weapon= ""}
// Default constructor, which creates a repository.
new () = new RobotsViewModel(new RobotsRepository())
// Implementing the INotifyPropertyChanged interface
// so the GUI can react to events.
interface INotifyPropertyChanged with
[<CLIEvent>]
member x.PropertyChanged = propertyChangedEvent.Publish
// Helper method to raise the property changed event.
member x.OnPropertyChanged propertyName =
let parameters: obj[] =
[| x; new PropertyChangedEventArgs(propertyName) |]
propertyChangedEvent.Trigger(parameters)
// Collection of robots that the GUI will data bind to.
member x.Robots =
robots
// Currently selected robot that the GUI will data bind to.
member x.SelectedRobot
with get () = selectedRobot
and set value =
selectedRobot <- value
x.OnPropertyChanged "SelectedRobot"
The first thing to notice about the RobotsViewModel is the two constructors. The first constructor accepts a RobotsRepository parameter so that the class can access the robot data. The rest of this constructor initializes fields that will be accessible to the rest of the class’ methods. After these fields have been initialized, we then define a second constructor, one without parameters, which must call the first constructor. We call the first constructor and pass it a new instance of our repository:
// Default constructor, which creates a repository.
new () = new RobotsViewModel(new RobotsRepository())
Now that we’ve seen both constructors, let’s take a look at each field we defined and how they are used in the class. First we define a field that will provide the backing store for our event handler. An event handler is needed to implement the INotifyPropertyChanged interface, which is how the ViewModel informs the view of changes. Creating the backing store is simple enough, we just need to create a DelegateEvent object and bind it to a field.
// Backing field of the on property change event.
let propertyChangedEvent =
new DelegateEvent<PropertyChangedEventHandler>()
What is more interesting than the backing store for the event is how we use the properyChangedEvent field. We use this field in two ways: to implement the event itself, and to create a method to raise the event. This is how we create the event by exposing the DelegateEvent.Publish property:
// Implementing the INotifyPropertyChanged interface
// so the GUI can react to events.
interface INotifyPropertyChanged with
[<CLIEvent>]
member x.PropertyChanged = propertyChangedEvent.Publish
We see here that the event is exposed as part of the implementation of the INotifyPropertyChanged interface which has just one member: the event PropertyChanged. We need to mark the PropertyChanged with a [<CLIEvent>] attribute so that the F# compiler knows it should generate an event compatible with other CLR languages, such as C#, as F# has its own optimized systems of events. Now that we have exposed the event, we need to be able to invoke the event. We do this by creating an OnPropertyChanged method that will trigger the event.
// Helper method to raise the property changed event.
member x.OnPropertyChanged propertyName =
let parameters: obj[] =
[| x; new PropertyChangedEventArgs(propertyName) |]
propertyChangedEvent.Trigger(parameters)
These three members of the class, the propertyChangedEvent field, the interface implementation of INotifyPropertyChanged, and the OnPropertyChanged method, would normally be placed in a base class so that they could be shared between all the ViewModels of the application. For the purposes of simplifying this example I’ve kept them in the same class as the ViewModel, as we only have one ViewModel in this application. The next two fields relate to properties that will be exposed to allow the view to bind to the ViewModel. The first field, robots, holds the collection of all robot data:
// Our collection of robots.
let robots =
let allRobots = robotsRepository.GetAll()
new ObservableCollection<Robot>(allRobots)
We’ve used an observable collection to represent the list of robots. This collection type will automatically notify the view if we add or remove items from the collection. We then expose this collection by a property:
// Collection of robots that the GUI will data bind to.
member x.Robots =
robots
This Robots property will be bound to a list view control in the GUI that will display the list of robots. The next field selectedRobot represents the currently selected robot.
// The currently selected robot
// initialized to an empty robot.
let mutable selectedRobot =
{Name=""; Movement=""; Weapon= ""}
The field needs to be mutable as it will change over time. As the user selects a robot the field will be updated. This update will occur because of the data binding that we’ll look at when we examine how the view is implemented. Again, we use a field to expose this property, but this time we need to provide both a getter and a setter:
// Currently selected robot that the GUI will data bind to.
member x.SelectedRobot
with get () = selectedRobot
and set value =
selectedRobot <- value
x.OnPropertyChanged "SelectedRobot"
The getter simply returns our field, but the setter must do two things. It must first update the field selectedRobot, and then call the OnPropertyChanged method to raise the property changed event that will notify the GUI of the change.
We’ve looked at everything that makes up the ViewModel, and now we’ll take a look at the view itself. As this view is more complex than the previous XAML views that we’ve seen, I think it would be helpful to first look at an image of the layout, then take a look at the complete XAML listing, and finally walk through the important points of the XAML. The XAML listing is quite long, but don’t worry about this too much. Most of the XAML just describes the positioning of the controls; there are only a few important bits that we need to examine in more detail.
First, let’s look at a screenshot of the application:

Figure 7: Robot Inventory Application
Here we see that the application is composed of a list box on the left side and some labels that show the details of the robot on the right side. As the user changes the selection, the details of the robot change.
This is what the full view listing looks like:
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:ViewModel="clr-namespace:FsSuccinctly.RobotsMvvm.ViewModel;assembly=Form_MVVM"
mc:Ignorable="d"
Width="350"
Height="300">
<!-- Create and data bind the ViewModel. -->
<Window.DataContext>
<ViewModel:RobotsViewModel></ViewModel:RobotsViewModel>
</Window.DataContext>
<Grid Margin="10,0,10,10" VerticalAlignment="Stretch">
<Grid.Resources>
<!-- Name item template. -->
<DataTemplate x:Key="nameItemTemplate">
<Label Content="{Binding Path=Name}"/>
</DataTemplate>
</Grid.Resources>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
</Grid.RowDefinitions>
<!-- Robots list. -->
<Label Grid.Row="0" Grid.ColumnSpan="2">
Robots Details Viewer
</Label>
<Grid Margin="10" Grid.Column="0"
Grid.Row="1" VerticalAlignment="Top">
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Border Grid.Row="1">
<Label>Names</Label>
</Border>
<ListBox Name="robotsBox" Grid.Row="2"
ItemsSource="{Binding Path=Robots}"
ItemTemplate="{StaticResource nameItemTemplate}"
SelectedItem="{Binding Path=SelectedRobot,Mode=TwoWay}"
IsSynchronizedWithCurrentItem="True">
</ListBox>
</Grid>
<Grid Margin="10" Grid.Column="1" Grid.Row="1"
DataContext="{Binding SelectedRobot}" VerticalAlignment="Top">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="57*" />
<ColumnDefinition Width="125*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<!-- Name -->
<StackPanel Grid.Column="0" Grid.ColumnSpan="2"
Grid.Row="0" Orientation="Horizontal">
<Label>Name:</Label>
<Label Content="{Binding Path=Name}"></Label>
</StackPanel>
<!-- Movement -->
<StackPanel Grid.Column="0" Grid.ColumnSpan="2"
Grid.Row="1" Orientation="Horizontal">
<Label>Movement:</Label>
<Label Content="{Binding Path=Movement}"></Label>
</StackPanel>
<!-- Weapon -->
<StackPanel Grid.Column="0" Grid.ColumnSpan="2"
Grid.Row="2" Orientation="Horizontal">
<Label>Weapon:</Label>
<Label Content="{Binding Path=Weapon}"></Label>
</StackPanel>
</Grid>
</Grid>
</Window>
As you can see, the list for the XAML view is quite long, but don’t worry, there are only a few key points to note. To begin with, let’s look at how the ViewModel is bound to the view. First we need an attribute in the Window tag to create an alias so we can access the ViewModel’s namespace:
xmlns:ViewModel="clr-namespace:FsSuccinctly.RobotsMvvm.ViewModel;assembly=Form_MVVM"
We can now use the prefix ViewModel to let us access classes in the FsSuccinctly.RobotsMvvm.ViewModel as tags in our XAML document. This means we can create an instance of the ViewModel and bind it to the view’s data context in XAML like this:
<!-- Create and data bind the ViewModel. -->
<Window.DataContext>
<ViewModel:RobotsViewModel></ViewModel:RobotsViewModel>
</Window.DataContext>
The next important part of the view is the list box that will display the robots, which is coded as follows:
<ListBox Name="robotsBox" Grid.Row="2"
ItemsSource="{Binding Path=Robots}"
SelectedItem="{Binding Path=SelectedRobot,Mode=TwoWay}"
ItemTemplate="{StaticResource nameItemTemplate}"
IsSynchronizedWithCurrentItem="True">
</ListBox>
This list box makes good use of WPF’s powerful data binding. We bind the ItemsSource property to the ViewModel’s Robot property so that the list box will display the list of robots. The SelectedItem property is bound to the SelectedRobot property. This takes advantage of WPF’s two-way bindings, meaning that as the user updates the selected item in the user interface, the SelectedItem of the list view is also updated, and thanks to the two-way binding the SelectedRobot property is also updated. The ItemTemplate property allows you to control how each item in the list box is rendered. In this case we reference a template we’ve defined earlier:
<Grid.Resources>
<!-- Name item template. -->
<DataTemplate x:Key="nameItemTemplate">
<Label Content="{Binding Path=Name}"/>
</DataTemplate>
</Grid.Resources>
Now that we’ve seen how the list box works, we just need to look at how the robot details are displayed. Here we show three fields of information about the robot, but each field that is displayed has the same implementation, so we only really need to look at how one field is implemented. The three fields are displayed in a grid; we bind this Grid tag to our SelectedRobot property from the ViewModel. This will give us easy access to the fields we want to display in the labels that show the details of our selected robot. The following shows how the grid is implemented. The important property to note here is the DataContext property:
<Grid Margin="10" Grid.Column="1" Grid.Row="1"
DataContext="{Binding SelectedRobot}" VerticalAlignment="Top">
Now let’s take a look at one of the fields within the grid. Here we see the implementation of the Name field:
<!-- Name -->
<StackPanel Grid.Column="0" Grid.ColumnSpan="2"
Grid.Row="0" Orientation="Horizontal">
<Label>Name:</Label>
<Label Content="{Binding Path=Name}"></Label>
</StackPanel>
We can see how the Content property of the second label is bound to the Name property of the robot. That’s all the important details of the view, and we’re almost finished with the implementation of our XAML form. The only thing remaining is to load the XAML view and display it. We can do this using the helper functions we defined earlier in the chapter. As you can see, it’s quite simple to load the XAML window and display it:
// Create the window.
let win = loadWindowFromResources "RobotsWindow.xaml"
// Create the application object and show the window.
let app = new Application()
[<STAThread>]
do app.Run win |> ignore
There is no need to wire up any events or do any other kind of configuration. The XAML view takes care of binding itself to the ViewModel that drives the rest of the interactions.
We’ve now seen how F# can be used in several different ways with WPF, including using WPF’s powerful MVVM design pattern. Hopefully this has given you a good idea how F# can be used in the creation of business applications that require structured data to be input by the user. We focused on WPF, but there many other GUI libraries available on the .NET framework. Although we have not seen specific examples for these libraries, most of them share similar concepts to WPF. Hopefully you will find some of the ideas in this chapter usable with other libraries.