Developing rich user interfaces using the MVC pattern - Developing complete systems - F# Deep Dives (2015)

F# Deep Dives (2015)

Part 3. Developing complete systems

In the previous part, we talked about using F# for implementing the core business logic, or analytical components of larger applications. As discussed in chapter 1, this is an area where the benefits of a functional-first approach are an easy sell.

But functional-first programming isn’t useful only for analytical components. Many developers and companies use it to build complete systems. If you’re an individual or have a small team that already knows F#, you can build incredible applications in F#, and you’ll benefit from the expressivity and safety of the language even when building games, user interfaces, or large concurrent systems.

In this part, you’ll see four examples: two focused on the front end and two on the backend side. In chapters 7 and 9, Dmitry Morozov and Johann Deneux talk about building UI-oriented applications: trading applications and games. You’ll see that F# lets you nicely handle difficult problems like data binding and implementing asynchronous game logic. In chapters 8 and 10, Simon Cousins and Yan Cui look at the backend, covering the agent-based programming model for data analytics and development of a server for social games.

You’ll see that the business cases discussed in chapter 1 also apply to the development of complete systems. When writing games, efficiency and the ability to get the game ready as soon as possible are crucial. Trading systems and concurrent data analyses are fundamentally complex systems, and F# lets you correctly solve problems that would be hard to tackle in other languages.

Chapter 7. Developing rich user interfaces using the MVC pattern

Dmitry Morozov

With the recent advance of mobile apps and web apps based on HTML5 and JavaScript, you might think that native desktop applications are no longer relevant. This couldn’t be further from the truth—the majority of business applications still run on the desktop. Many domains still require sophisticated user interfaces; they need to perform complex computations efficiently (benefiting from multiple CPUs) and display rich, interactive visualizations.

Two things are crucial for the development of rich desktop applications. First, you need a powerful framework that allows you to build the best user experience by taking full advantage of the capabilities of the underlying system. For Windows, Extensible Application Markup Language (XAML) based frameworks (Windows Presentation Foundation [WPF], Silverlight, and Windows Runtime) are the de facto choice. Second, you need a programming language that makes it easy to express the domain model and encode complex user interactions.

From a business perspective, the most important reason for adopting F# for desktop UI development is handling complexity. User interface development isn’t easy, and you need a language that lets you build the right abstractions. At the same time, the rich type system of F# gives you manycorrectness guarantees.

The most common way to structure the code base of XAML applications is the well-known Model-View-ViewModel (MVVM) pattern (see the sidebar “State of the Art: The MVVM Pattern”). But in this chapter, you’ll use a different approach that allows you to benefit from F#’s strengths. The examples build on my experience developing an F# Model-View-Controller (MVC) framework.[1] I’ll show you how to build the entire application from the beginning.

1 My series “F# MVC Framework for WPF” is available at http://mng.bz/ZCKC. If you feel like exploring concepts of developing a WPF GUI in F#, I encourage you read the series in full.

State of the art: the MVVM pattern

The MVVM pattern can be used with F#, but it was originally designed and optimized for C#/VB.NET and so doesn’t take advantage of many unique features that F# brings to the table. In particular, it doesn’t let you benefit from immutability, a powerful type system, and a functionally oriented computation model. That’s why this chapter builds on the MVC pattern—another pattern that is often implemented in UI applications.

MVVM is a variation of Martin Fowler’s Presentation Model pattern. It follows the classic object-oriented programming (OOP) approach where state and behavior are combined in one monolithic object (ViewModel). This makes the pattern inappropriate for function-first languages such as F# where immutable state is separated from behavior.

The MVVM pattern

In MVVM, the state between View and ViewModel is synchronized by data binding. Events are communicated to the ViewModel via the command mechanism. Commands are limited, so developers must use a direct event subscription or another extension technique called behaviors. This variety makes event processing non-uniform and therefore hard to compose, test, and reason about. In addition to the visual state (usually properties participating in data binding), the ViewModel usually contains an operational state like a database connection or web service proxies. This adds another level of complexity to an already far-from-simple combination of logic and mutable state.

Commands, bindings, and behaviors represent a form of coupling, but all of them bypass a type system because they’re expressed in terms of object type. It makes them implicit runtime dependencies, which are the trickiest of all to track.

GUI development is a vast topic and can’t be fully covered in one chapter. I’ll focus on a way to organize logic around individual screens that’s different from the MVVM pattern. To do so, let’s go back to the roots and use a variation of the MVC pattern.[2]

2 The closest pattern is probably Martin Fowler’s Supervising Controller.

Setting the scene

As an example, I put together a trading application that’s simple enough to be covered in one chapter and yet has a “real world” touch. This section introduces the trading application. You’ll also explore the MVC pattern, which will define the structure underlying the implementation.

The trading application

After the application starts, the user enters a tradable security symbol (such as MSFT) and clicks the “i” button to retrieve security information from Yahoo. Selecting the Price Feed Simulation check box activates a feed from one year ago to the current day (Yahoo historical pricing). The button in the Position Management section shows the current price and available action: Buy or Sell. On the right, a chart displays the price history (see figure 1).

Figure 1. The sample application: the user has entered a security symbol and started the price feed.

The next step a user can take is to open a position. The available action changes from Buy to Sell, and the chart is divided into two areas: profit (light green) and loss (light red). The profit and loss (P&L) value for the open position is either red (under water) or green. At this point, a user can choose to close the position manually or set up Stop Loss At and Take Profit At thresholds. Once the position is closed, no actions can be taken on it (see figure 2).

Figure 2. The position is closed.

As mentioned earlier, the application design is based on the MVC pattern. Before I delve into the details of the individual components for the trading application, let’s look at a simple example that demonstrates how the components look and interact in the functional setting.

Introducing the MVC pattern

The MVC pattern is a set of components for building a UI. The key idea is Model-View and View-Controller separation (see figure 3).

Figure 3. MVC pattern

Event processing is at the heart of any GUI application. F# embraces events as first-class values. For example, they can be passed in or out of functions, or they can make up collections. Event streams are particularly useful because they can be transformed and composed in a familiar functional style. With this concept in mind, let’s describe the hypothetical, purely functional architecture behind a UI widget that’s a numeric up/down control, like the one shown in figure 4, using only types:

Figure 4. Numeric up/down control

This design is dramatically different from MVVM. It has a functional twist: the model is immutable, the view exposes an event stream, and the events are modeled using a discriminated union. Functional gurus may spot remarkable similarity between the Mvc type and Seq.fold. Interestingly, you can get a pretty good idea of the application structure just by reading the type definitions. Describing design intent with types may seem unusual to somebody accustomed to methods like UML, but it makes sense—functional types are succinct and won’t go out of date as your application evolves.

This architecture is a good starting point, but it’s impractical to use. The immutable model is incompatible with data binding, which XAML relies on heavily. With some improvements, the model looks like this:

type UpDownEvent = Incr | Decr

type View = IObservable<UpDownEvent>

type Model = { mutable State : int }

type Controller = Model -> UpDownEvent -> unit

type Mvc = Controller -> Model -> View -> IDisposable

All the components are well separated: Model can be any type, View is an interface generalized by the UpDownEvent type, the Controller function applies Event to Model by mutating state, and Mvc is a mediator that glues all the pieces together. A type parameter for View has no special constraints, but it’s best expressed as a discriminated union. It allows you to represent different events raised by a single view. A concrete implementation of the pattern for the up/down control looks like this:

When this code snippet is executed in FSI, it outputs the following:

Model: {State = 7;}

Model: {State = 6;}

Model: {State = 7;}

Controller pattern-matches on the UpDownEvent to provide case-specific processing logic. If one of the cases isn’t handled (try to comment out the Increment case, for example), the compiler warns, “Incomplete pattern matches.” This compiler-checked event handling enables a clean, loosely coupled, yet cohesive architecture.

Defining the modelCastle.Core libraryINotifyPropertyChanged inter- rfacemodel (MVC pattern)MVC (Model-View-Controller) patternmodelPropertyChanged eventThe term model here means a presentation model, not a domain model.

To support data binding between the WPF UI and the model, the type representing the model needs to implement the INotifyPropertyChanged interface. This notifies the view when the values of the model change so that it can be automatically updated.

Naive implementations of INotifyPropertyChanged often suffer from tedious and error-prone invocations to raise the PropertyChanged event inside the setter of every single property. A clever way to avoid this is to use dynamic proxy interception. Proxy objects allow calls to virtual members (including property setters) of an object to be intercepted without modifying the code of the class. In the postprocess phase, the interceptor raises the PropertyChanged event.

Tip

Castle DynamicProxy is a component for generating lightweight .NET proxies on the fly at runtime. It’s part of the bigger Castle.Core library available via NuGet (www.nuget.org/packages/Castle.Core).

To use dynamic proxy interception, you need to write the code as follows:

· A property eligible for interception must be defined as virtual (or abstract).

· The factory method Model.Create must be used to create a model instance.

· Application-specific models must inherit from the base model type and have a parameter-less constructor.

When you’re dealing with dynamic invocations, some reflection-based coding is inevitable. To avoid duplication and make it more palatable, you can create some helpers.

Listing 1. Helper active patterns for implementing interception

Now you can implement the base type for custom models with the Create factory method, which sets up interceptors.

Listing 2. Base class for implementing models

In comparison to a typical base model definition, this requires more code. The ability to provide backend storage for purely abstract properties adds extra complexity. But the payoff is obvious for any application of reasonable size. Defining custom models is a breeze:

type PositionState = Zero | Opened | Closed

[<AbstractClass>]

type MainModel() =

inherit Model()

abstract Symbol : string with get, set

abstract InstrumentName : string with get, set

abstract Price : Nullable<decimal> with get, set

abstract PriceFeedSimulation : bool with get, set

abstract PositionState : PositionState with get, set

abstract IsPositionActionAllowed : bool with get, set

abstract PositionSize : int with get, set

abstract OpenPrice : Nullable<decimal> with get, set

abstract ClosePrice : Nullable<decimal> with get, set

abstract PnL : decimal with get, set

abstract StopLossAt : Nullable<decimal> with get, set

abstract TakeProfitAt : Nullable<decimal> with get, set

This type definition is as close as it gets to declarative data structures (similar to F# records with mutable fields). With a fairly small amount of code in listing 2, you can build the right abstractions. Once you have the abstractions in place, handling the complexity of the model implementation is an easy task—if you decide you need to include more properties in the model, it’s just a matter of adding a single line! Now, let’s look at the view part of the MVC pattern.

Implementing the main trading view

The view plays two vital roles: the event source and the data binding target. You start by implementing a reusable interface that represents a view. In the sample application you create only a single concrete view, but you could easily add more screens showing different aspects of the trade. The interface is as follows:

A concrete implementation of the view needs to provide two members: the Set-Bindings member takes a model as an argument and is responsible for setting up data bindings that update the view when the model changes, and the Events member exposes to the controller events that happen in the UI. Although the interface is fully generic in both event and model types, you should always use discriminated unions to represent the type of events. This gives you a powerful way to report events that’s difficult to achieve in classic OOP languages.

Note

At first it may seem that discriminated unions can be replaced with standard .NET enumeration types. This isn’t true. First, enumeration types don’t work smoothly with pattern matching.[4] Plus, it’s often useful to pass additional event data to a handler. Discriminated-union cases may carry extra information, but enumeration cases can’t.

4 For details, see Scott Wlaschin, “Enum types,” F# for Fun and Profit, July 9, 2012, http://fsharpforfunandprofit.com/posts/enum-types.

You can define a view implementation in many different ways, but this chapter uses a mixed F#/C# approach. C# projects are used only to host XAML definitions and generate static types for WPF windows or controls. I won’t go into the details of the XAML part of the application, but let’s briefly discuss the most important parts.

The implementation of the IView<'TEvent, 'TModel> interface in listing 3 is where the most interesting things happen. There is no need for the Observable.FromEventPattern factory that’s frequently used in C#, because the F# compiler automatically maps all .NET events toIEvent<'T>, which is inherited from IObservable<'T>.

Listing 3. IView implementation in the sample application

The theme of first-class events pops up again in the implementation of the Events property. Notice how easily events can form standard lists or be transformed via Observable.map or combined via Observable.merge.

There are other options for implementing the XAML-based view. In addition to adding a C# project, you could use the dynamic lookup operator (?) or the XAML type provider to get a statically typed view of elements in an embedded XAML file. Now, let’s move on to the last component of MVC: the controller.

Handling interactions in the controller

The controller is the chief component of MVC because it contains most, if not all, of the presentation logic. Its essential responsibility is to execute event-specific computations while reading and updating the model state in process. The simplest variation of the controller is the event-handling function of type ('TModel -> 'TEvents -> unit), as you saw earlier.

Most screens in GUI applications aren’t empty when first opened—they display information immediately. This means the view model needs to be initialized. Suppress your initial instinct, inherited from the good old OOP days, to put the model initialization logic in the model’s constructor. This practice forces the model to have dependencies on external resources such as database connections and web services, and eventually testability will suffer. Placing this code in the controller’s InitModel and employing the principle of dependency inversion helps. Ideally, the model is a purely declarative data structure and contains no logic. This is a typical separation for a functional paradigm. To encourage external initialization, a parameter-less constructor constraint exists on model implementation.

With these requirements in mind, you can define the controller interface as follows:

type IController<'TEvent, 'TModel> =

abstract InitModel : 'TModel -> unit

abstract EventHandler : 'TModel * 'TEvent -> unit

The concrete controller has a dependency on an external service that validates an instrument symbol and resolves it to a company name. The following default sample implementation uses Yahoo Financial Services.

Listing 4. Default Symbology service implementation

module Symbology

open System

let yahoo symbol =

use wc = new Net.WebClient()

let yahoo = "http://download.finance.yahoo.com/d"

let uri = sprintf "%s/quotes.csv?s&f=nl1" yahoo symbol

wc.DownloadString(uri)

.Split([| "\n\r" |], StringSplitOptions.RemoveEmptyEntries)

|> Array.map (fun line ->

let xs = line.Split(',')

let name, price = xs.[0], xs.[1]

if price = "0.00" then None else Some name

)

|> Seq.exactlyOne

The implementation of the controller in the next listing contains core application logic: resolving the stock symbol, starting the price feed, entering and exiting positions, and displaying metrics.

Listing 5. IController implementation in the sample application

Here are the key points about this implementation:

· The model initialization includes an invocation to an external symbol-resolution service. This dependency is well controlled and isolated to one type. For example, it can be replaced with a fake during testing. Imagine this initialization logic moved to the model constructor: it would turn the model from a simple declarative data structure into a nontrivial class with imperative logic and complex dependencies. The overall architecture would become spaghetti-like.

· When a pattern matches on different event cases, the compiler warns you if you miss any. This makes it a compiler-checked map.

· Writing a unit test for a specific event is as easy as calling a method like GetInstrumentInfo. External dependencies like a database connection still need to be mocked. There is little value in unit testing the EventHandler method because it’s mostly done by type system (again!) and the compiler.

Gluing together the MVC pieces

Now that all the components are defined, you need to connect them, start the event loop, and coordinate event processing. Technically these responsibilities can be assigned to the controller. You could create a base class, put this logic there, and require all controllers to inherit from this class, but doing so would lead to fragile subclass coupling. A better solution is to define a separate component that plays the mediator/coordinator role (see figure 5).

Figure 5. The F# MVC for WPF framework

We’re about to wrap up this section, so let’s look at the main module that starts the application, together with the relevant interfaces (discussed earlier) from the core framework.

Listing 6. MVC

type IView<'TEvent, 'TModel> =

abstract Events : IObservable<'TEvent>

abstract SetBindings: model : 'TModel -> unit

type IController<'TEvent, 'TModel> =

abstract InitModel: 'TModel -> unit

abstract EventHandler: 'TModel * 'TEvent -> unit

module Mvc =

let start (model: #INotifyPropertyChanged,

view: IView<_, _>,

controller: IController<_, _>) =

controller.InitModel model

view.SetBindings model

view.Events.Subscribe(fun event ->

controller.EventHandler(model, event))

I think it’s impressive how much you can express in about a dozen lines of code without losing clarity. Even though developing UIs is a complex task, a simple type definition using first-class events (IObservable<'T>) and discriminated unions (when implementing the view) saves the day!

To finish the application, you just need to add a new file with the main function:

[<STAThread>]

[<EntryPoint>]

let main _ =

let mainWindow = MainWindow()

let mvc = Model.Create(), MainView mainWindow, MainContoller()

use eventLoop = Mvc.start mvc

Application().Run(mainWindow)

Table 1 sums up the roles of the individual components.

Table 1. Roles of the individual components

Component

Responsibilities

Collaboration

Model

Holds state

The model carries a subset of the view state projected via data binding. Data binding is the key responsible for synchronizing the model with the view, hence the INotifyPropertyChanged constraint in the Mvc.start type signature. Follow best practices of functional programming, and keep the model declarative (dumb, if you prefer this term). Avoid presentation logic in the model—it belongs in the controller.

View

Event source Data-binding target

Events Model

The view hides details of the underlying GUI framework behind a generic and simple IView<'TEvent,'TModel> interface. This interface is an example of both parametric polymorphism (by 'TEvent type, which allows you to define a single generic implementation of the Mvc type) and subtype polymorphism (which uses different IView implementations).

Controller

Event processor

Events Model

The controller is dependent only on events and the model. It makes the architecture loosely coupled (and therefore more testable) yet cohesive (pattern matching ensures that all event cases are handled).

Mvc

Mediator Coordinator

Events Model IView Controller

The Mvc type depends on everything, but it doesn’t matter because it stays fixed. There is no need to extend or change it.

So far, you’ve looked at the overall architecture of an MVC application and seen how to build a simple application. I could end the chapter now, but doing so would leave out many aspects that are important in the real world.

Living in an asynchronous world

There is no need to explain the importance of asynchronous programming. These days it’s everywhere, whether you want to express complex interaction logic using asynchronous programming models, or your application retrieves data from the web or calls REST-based APIs. In any case, you need asynchronous programming to avoid creating applications that block the UI and become unresponsive.

F# was one of the earliest mainstream languages to provide first-class support for asynchronous programming. Support in the context of the MVC framework developed in this chapter means first and foremost using asynchronous event handlers in addition to synchronous ones.

Designing software with types

There is a popular opinion that statically typed languages are all about program correctness—verification and tooling support (IntelliSense, refactoring, and so on). This isn’t 100% accurate. Using static types is a great vehicle for design and exploration that lets you handle program design complexity. These capabilities are often overlooked. Exploration plays an important role when you’re starting to work with an unfamiliar code base. Design comes along during the construction or refactoring phase.

First, let’s walk through the same design process I used when facing the task of supporting asynchronous computations in the framework. Keep a close eye on how types guided me through the process. Here are the refactoring steps toward the final solution:

1. Redefine EventHandler as a curried F# function as you did earlier:

abstract EventHandler : ('TModel -> 'TEvent -> unit)

2. Change the order of the arguments, moving the model to the end:

abstract EventHandler : ('TEvent -> 'TModel -> unit)

3. When I saw the new type signature, a light bulb went off in my head. F# functions are right-associative. So, the previous signature can be replaced with this:

abstract EventHandler : ('TEvent -> ('TModel -> unit))

Now it becomes obvious that this is not only an event handler but something bigger: it’s an event-handler factory. When partially applied to the first argument of type 'TEvent, it returns a handler for a specific case.

4. Let’s separate the event handler into a standalone type. Doing so will make it possible to introduce two kinds of event handlers (synchronous and asynchronous) in the next step:

type EventHandler<'TModel> = 'TModel -> unit
type IController<'TEvent, 'TModel> =
abstract InitModel: 'TModel -> unit
abstract Dispatcher : ('TEvent -> EventHandler<'TModel>)

5. How do I define two kinds of event handlers? With a discriminated union. Bingo!

What did I arrive at in the end? You can see the final result in the following listing.

Listing 7. Controller and Mvc with support for asynchronous programming

The Async.StartImmediate method starts the asynchronous computation on the invocation thread. This is important because it allows you to capture a synchronization context that you can later use to continue the GUI thread.

In the sample application, there is an invocation to a remote service that validates the instrument symbol the user entered (the default implementation goes to the Yahoo service). It’s certainly better to use asynchronous computation to keep the UI responsive, as shown in the next listing.

Listing 8. Sample controller implementation with Async

Here are the key points about listing 8:

· The .NET method EventHandler is replaced by the Dispatcher property of type function. The new name reflects the nature of this function best: it dispatches the event to the proper event handler.

· The new implementation of Dispatcher in MainController takes advantage of all changes. It’s now a high-order pattern-matching function. I can’t imagine a more expressive implementation.

· For multiparameter event-handler implementations (like UpdateCurrentPrice), partial function application is simpler when the model is the last parameter.

· Don’t forget to include an invocation to Async.SwitchToContext to make sure the UI is updated in the proper thread.

The need to validate security symbols asynchronously may not be convincing enough for you. But remember, this is a sample application with limited scope. Imagine trading many securities at once. If the GUI is blocked while pulling information about one security when a user needs to sell another, money can be lost. If it’s still not appealing to you, then think of environments like Silverlight where a network call is always asynchronous, or Windows Runtime, where any timely (more than 50 ms) invocation is asynchronous.

We wouldn’t be able to arrive at such a simple and elegant solution without types. Look at C#, which has a weaker type system and computational model. Version 5.0 introduced support for asynchronous computation that surfaces in the form of the async and await keywords. At first glance it seems identical to F#, but when you dig deeper, the difference between the type system–based and compiler “black magic” approaches becomes obvious. It’s relevant to GUI programming. The return type async void exists only to support asynchronous event handlers. This creates a famous issue of async void versus async Task return-type semantics; Tomas Petricek has a detailed blog post on the subject.[5] For skeptics, I suggest the following: try implementing something similar to what I’ve shown you in this chapter in C#.

5 Tomas Petricek, “Async in C# and F#: Asynchronous gotchas in C#,” Tomas Petricek’s Blog, April 15, 2013, http://tomasp.net/blog/csharp-async-gotchas.aspx.

Exercise 1

The current implementation lacks exception handling. This is especially confusing for asynchronous event handlers because exceptions are ignored. Your task is to extend Mvc.start to save exceptions into an event log or file. Try to preserve an accurate stack trace.

Exercise 2

Sometimes GUI applications have a heavy model initialization because they load a lot of data or perform intense computations. Users get annoyed when they have to wait a long time for the screen to appear initially. Your task is to address this issue by splitting Controller.InitModelinto two parts: synchronous and asynchronous. The type signature of Controller.InitModel must be preserved.

Exercise 3

Introduce support for canceling long-running asynchronous invocations.

Making data binding safer

Data binding is a mechanism that ensures that any change made to the data in a UI control is automatically carried over to the view model (and vice versa). Traditionally, the property names of source objects are passed as strings. This can be done either in XAML

<TextBox Name="PositionSize" Text="{Binding PositionSize}"

or in code:

window.Symbol.SetBinding(TextBox.TextProperty, "Symbol") |> ignore

Are magic strings the only choice?

Let’s have another look at the IView interface:

type IView<'TEvent, 'TModel> =

abstract Events : IObservable<'TEvent>

abstract SetBindings : model : 'TModel -> unit

In the previous section, you didn’t use the fact that the interface is also generic in the type of the model (called 'TModel). You just passed the model as a value for Data-Context, which accepts any object. But when you perform data binding that way, the type goes unnoticed by the type system. Therefore, helpful things like compiler verification and tooling support (IntelliSense, refactoring, and so on) are missing.

Here’s a simple example that illustrates the problem. Let’s say that during refactoring you rename the Price property of the model to CurrentPrice. You fix obvious compilation errors and then compile and run the program. A strange thing happens: there is no exception, but the current price doesn’t show a value. A careful search through hundreds of lines in the debug output window in Visual Studio reveals the following message:

System.Windows.Data Error: 40:

BindingExpression path error: 'Price' property not found on 'object'

I’m sure many WPF, WinRT, and Silverlight developers have gone through this painful experience. This happens whether bindings are set programmatically or in XAML. In my opinion, defining bindings in XAML is a worse option because it erases all the benefits of the separation between declarative XAML and application logic.

Are magic strings the only choice? Of course not. Let’s see how you can handle data binding in a statically typed way using the F# quotation mechanism.

Introducing statically typed data binding

Begin by mapping the quoted F# assignment statement

<@ symbol.Text <- model.Symbol @>

to the data binding setup call:

symbol.SetBinding(TextBox.TextProperty, "Symbol")

The following listing shows a fairly simple implementation.

Listing 9. Mapping the assignment statement to the data-binding expression

Here is the actual invocation in the MainView type:

Binding.ofExpression <@ symbol.Text <- model.Symbol @>

Neat. Next let’s try binding for the PriceFeedSimulation.IsChecked property as a target.

Handling nullable values in data binding

Unfortunately, the compiler gives an error (see figure 6) because the left side is of type Nullable<bool> but the right is bool. There are two ways to fix this issue. The first is to change the PriceFeedSimulation property type on the model to Nullable<bool>. This is slightly inconvenient because you know the property can’t be null. The second option is to insert a fake call to the Nullable<bool> constructor inside the quotation, discard it at runtime, and let the WPF data-binding engine handle the conversion.

Figure 6. Mismatch between source and target property types

Let’s try the second approach:

Binding.ofExpression

<@

priceFeedSimulation.IsChecked <- Nullable model.PriceFeedSimulation

@>

Unfortunately, this approach fails because the quotation-parsing logic isn’t prepared to handle it. To refactor it to a working solution (see listing 10), you need to make the following changes:

· Extract logic that finds a companion dependency property for the regular .NET property.

· Support quotations containing more than one assignment statement.

· Delegate parsing the parts of the assignment statement quotations to helpers. Figure 7 shows the correspondence between the key components of binding, parts of a single assignment statement, and items available after decomposition using the PropertySet active pattern.

Figure 7. Assignment statement deconstructed

Listing 10. Refactored typed data binding

Listing 10 refactors the quotation-processing logic into small functions that are easy to understand. The issue of mapping the model property of type bool to control the property of type Nullable<bool> is handled by the second case in (|Source|_|). It matches the invocation to theNullable constructor, discards it, and recursively invokes (|Source|_|) again. The compiler is happy and runtime semantics are managed by WPF data binding. This can be confusing, because the actual runtime behavior can differ from what you’d expect when you look at the code. It’s certainly a deviation from the full fidelity type system, but it’s significantly better than magic strings.

Note that the implementation would be verbose and error-prone without the entire set of F# language features: pattern matching, active patterns, recursive definitions, extension properties, and of course type inference.

Handling conversions

You now have several TextBox controls that represent numerical values. For example, let’s try PositionSize:

Binding.ofExpression <@ positionSize.Text <- model.PositionSize @>

The attempt to bind fails, and you see the error message “This expression was expected to have a type string but here has type int.” This is similar to the earlier problem of the bool and Nullable<bool> mismatch. But this issue has a different angle:XAML controls have most of their properties defined in terms of generic obj or string types. It makes them widely applicable but typeless. As in the previous case, there two ways to solve the problem: you can define the model property of the matching type or insert a type conversion “shim” to satisfy the compiler. Both approaches have pros and cons, but the second requires less manual coding because WPF does many conversions behind the scenes. To make it work, the following listing introduces a pseudo-function called Binding.coerce and makes a small change in (|Binding-Instance|_|).

Listing 11. Mapping typed properties of the model to strings

This solution diminishes the value of the F# type system because an instance of any type can pass through the coerce function. But whatever is left is still valuable and makes trying the approach worthwhile. Plus, this extreme method doesn’t have to be used often. I expand on the topic of conversions later in the chapter.

The WPF Binding type allows formatted output via a property called String-Format. It’s used to show the security name retrieved from Yahoo’s symbology service:

let binding = Binding(path = "InstrumentName", StringFormat = "Name : {0}")

instrumentName.SetBinding(TextBlock.TextProperty, binding) |> ignore

Converted to the new notation, it looks like the following:

Binding.ofExpression

<@

instrumentName.Text <- String.Format("Name : {0}", model.InstrumentName)

@>

You can include a small change in the quotation-parsing logic to handle the new case:

let rec (|Source|_|) = function

...

| SpecificCall

<@ String.Format: string * obj -> string @>

(

None,

[],

[ Value(:? string as format, _);

Coerce( Source binding, _) ]

) ->

binding.StringFormat <- format

Some binding

...

Note how a single line of pattern matching replaces dozens of lines of the Visitor pattern commonly used to traverse expression trees in mainstream OOP languages. A savvy F# developer might ask, “Why not use the F# native sprintf function inside the quotation rather than the .NET BCL String.Format”?” Unlike sprintf, String.Format has a straightforward mapping to the StringFormat property of the Binding type. Later, in the “Heavy Lifting: Derived Properties” sidebar, I’ll show you how to apply sprintf to build formatted output.

Adding transformations

Setting up bindings in XAML has a drawback: it’s impossible to add transformation logic. An example from the sample application is the position state (zero, opened, or closed) on the model mapped to the label on the action button. Table 2 shows the button labels and the corresponding position states they represent.

Table 2. Button labels and states

Button label

Value of PositionState model’s property

Zero (Empty)

Opened

Closed

Luckily, you set up data binding programmatically. The workaround is to use a converter, as shown next.

Listing 12. Typeless data binding with transformation done via a converter

actionText.SetBinding(

Run.TextProperty,

Binding("PositionState", Converter = {

new IValueConverter with

member this.Convert(value, _, _, _) =

match value with

| :? PositionState as x ->

match x with

| Zero -> "Buy"

| Opened -> "Sell"

| Closed -> "Current"

|> box

| _ -> DependencyProperty.UnsetValue

member this.ConvertBack(_, _, _, _) =

DependencyProperty.UnsetValue

})

) |> ignore

Although the converter implementation is fairly succinct thanks to F# object expressions, this code still doesn’t look pretty. With a new code-oriented approach, there must be a better way to express it. The next listing shows a minor change in (|Source|_|):

Listing 13. Parsing the source value transformation function

let rec (|Source|_|) = function

...

| Call(None, method', [ Source binding ]) ->

binding.Mode <- BindingMode.OneWay

binding.Converter <- {

new IValueConverter with

member this.Convert(value, _, _, _) =

try method'.Invoke(null, [| value |])

with _ -> DependencyProperty.UnsetValue

member this.ConvertBack(_, _, _, _) =

DependencyProperty.UnsetValue

}

Some binding

Equipped with the new logic, you can write a mapping function and apply it in the binding expression:

let positionStateToAction = function

| Zero -> "Buy"

| Opened -> "Sell"

| Closed -> "Current"

...

Binding.ofExpression

<@

actionText.Text <- positionStateToAction model.PositionState

@>

The mapping function can also be static or an extension method as long as it follows the type signature ‘a -> ‘b, where ‘a is a type of model property and ‘b is a type of control property. As another example, the next two listings show how you can use this function to map the model profit and loss (PNL) value to the pnl TextBlock’s font color.

Listing 14. Mapping the PNL value to font color via a traditional binding converter

pnl.SetBinding(

TextBlock.ForegroundProperty,

Binding("PnL", Converter = {

new IValueConverter with

member this.Convert(value, _, _, _) =

match value with

| :? decimal as x ->

if x < 0M then box "Red"

elif x > 0M then box "Green"

else box "Black"

| _ -> DependencyProperty.UnsetValue

member this.ConvertBack(_, _, _, _) =

DependencyProperty.UnsetValue

})

) |> ignore

Listing 15. Mapping the PNL value to font color in the binding expression

type MainView ...

static member GetColorForPNL x =

let color =

if x < 0M then "Red"

elif x > 0M then "Green"

else "Black"

BrushConverter().ConvertFromString color |> unbox<Brush>

...

Binding.ofExpression

<@

pnl.Foreground <- MainView.GetColorForPNL model.PnL

@>

Another popular approach is to define a separate property on the model and update it in the controller (ViewModel in MVVM) along with the property it depends on. In the example application, the IsPositionActionAllowed property by default is true but switches to false once the position is closed (as shown earlier in listing 5). The Buy / Sell / Current button’s IsEnabled property is bound to the IsPositionActionAllowed value. The next listing simplifies the logic by using an extension property[6] as a converter.

6 It could also be an extension method.

Listing 16. Replacing the model property and controller logic with a converter

The mapping functions in listing 16 are clearly separated and can therefore be easily unit-tested. It’s tempting to return the color as a string[7] instead of an instance of type Brush from the PnlToColor method and to have Binding.coerce(MainView.Pnl-ToColor model.PnL) on the right side of the binding expression. This works, but why cheat on the type system? As mentioned earlier, this nasty trick with the Binding .coerce function isn’t required often.

7 WPF uses the default conversion logic.

Implicit conversion (done by WPF behind the scenes) works well only for one-way bindings. For two-way bindings, I strongly recommend avoiding implicit or explicit converters (converters that implement both the Convert and ConvertBack methods). Here’s an example that shows why. Suppose a user follows this workflow to open a position:

1. The user enters a symbol (GOOG) and starts the price feed.

2. The user enters 12 as the position size.

3. The user enters 770 as the Stop Loss At limit.

4. The user switches back to position size, intending to change it, but accidentally clears it.

5. The user clicks the Buy button.

6. The position was opened with size 12, and the error message “could not be converted” and a red border around the Size field clearly indicate a user input error (see figure 8).

Figure 8. Problem with two-way converters

What happened here? The explanation is simple: the built-in WPF text-to-number converter threw an exception, conveying this information to the view but not to the model. Therefore, the controller was completely unaware of any user input errors. The key takeaway? Two-way converters are dangerous.

To wrap up, the following listing shows all the typed data bindings for the example application. For simplicity, I skipped some corner cases and minor details that are necessary for a production-quality typed data-binding library.

Listing 17. All the typed data bindings for the example application

Binding.ofExpression

<@

symbol.Text <- model.Symbol

instrumentName.Text <-

String.Format("Name : {0}", model.InstrumentName)

priceFeedSimulation.IsChecked <- Nullable model.PriceFeedSimulation

positionSize.Text <- Binding.coerce model.PositionSize

action.IsEnabled <- model.PositionState.ActionAllowed

actionText.Text <- positionStateToAction model.PositionState

price.Text <- Binding.coerce model.Price

``open``.Text <- Binding.coerce model.Open

close.Text <- Binding.coerce model.Close

pnl.Text <- Binding.coerce model.PnL

pnl.Foreground <- MainView.GetColorForPNL model.PnL

@>

I think you’ll agree that this is a significant improvement over the earlier attempts in terms of readability and safety.

Heavy lifting: derived properties[8]

The data-binding transformations introduced earlier are a handy feature. They allow you to run mapping computations every time the property changes. But this can be limiting. What if you need to execute a computation in response to a change in a set of properties? So far, you’ve had to keep those inside the controller. A specific example is the PNL calculation. Somewhere in the controller is the following code:

model.PnL <-

let x = decimal model.PositionSize *? ( model.Price ?-? model.Open)

x.GetValueOrDefault()

The PNL calculation depends on three other properties of the model: position size, current price, and open price. If any of these values change, PNL has to be recalculated. Because these changes can be caused by different events, the calculation needs to be handled in more than one place in the controller’s code. This quickly becomes a daunting task and can lead to duplication and errors.

An elegant solution to this problem is a feature called derived properties. You define a regular property on the model and mark it with DerivedPropertyAttribute, which is defined as a type alias of ReflectedDefinitionAttribute:

[<DerivedProperty>]

member this.Pnl =

let x = decimal this.PositionSize *? ( this.Price ?-? this.Open)

x.GetValueOrDefault()

There is a limitation: the derived property type must exactly match the target property type. A converter can’t be applied to it. You could make model.Pnl of type string, but you’ll see in a moment why doing so isn’t a good idea. How do you bind it to the TextBlock.Text property of type string? The easiest solution is to use StringFormat. Now you have a normal property that fires the PropertyChanged event and is recalculated every time any dependencies change. It’s a normal-looking .NET property that can be unit-tested for complex calculations. This is different from other approaches that use Microsoft intermediate language (MSIL) rewriting.

Properties that have transitive dependencies on other derived properties must be marked as derived too. Remember, you had a binding mapper that calculated color based on the PNL numeric value to emphasize profit (green), loss (red), or neutral (black). The only option you have is to create another derived property, because the converter can’t be applied to the PnL property anymore. The derived property Pnl2Color has a transitive dependency on the other derived property PnL. That’s why you keep the PnL property of the decimal value as opposed to the string:

open System.Windows.Media

type MainModel with

[<DerivedProperty>]

member this.Pnl2Color =

let color =

if this.PnL < 0M then "Red"

elif this.PnL > 0M then "Green"

else "Black"

BrushConverter().ConvertFromString color |> unbox<Brush>

Binding.ofExpression

<@

actionText.Text <- model.PositionState.ToAction()

pnl.Text <- String.Format("{0}", model.PnL)

pnl.Foreground <- model.Pnl2Color

@>

F# type-safe string formatting can be used inside derived properties instead of the .NET BCL String.Format. For example, another way to bind the PNL value to the control property of type string is to define another derived property that converts decimals to strings:

Using derived properties is a natural fit for complex formatting because more than one property can be referenced without losing support for the automatic PropertyChanged notification.

Although they come with minor restrictions, derived properties are a powerful feature and save you from writing a lot of boilerplate code. Declarative in nature, derived properties don’t contradict the idea of a controller as a central repository for presentation logic.

8 Due to space constraints, I’ll skip the implementation details and focus on usage. Curious readers are welcome to check this chapter’s source code.

Exercise 4

Extend type-safe data binding to accept expressions on the right side. For example:

Binding.ofExpression

<@ action.IsEnabled <- model.PositionState <> Closed @>

Allow only a single model property to be used in computation. Multiproperty expressions should be handled using derived properties.

Summary

I believe GUI programming is inherently hard. The essential complexity in GUI applications is caused by the fact that interactions between a human and a computer are far more informal and subtle than between two computers. Unfortunately, in the software industry, responding to complexity often results in even more of it. The original rise in popularity of OOP was due to its ability to create and manage deep hierarchies of classes with hundreds of mutable properties that tune the behavior of specific UI gadgets. As a modern language, F# provides innovative tools to tame such complexity. It combines these tools with fundamental concepts like functional programming and a powerful type system. One of the key strengths of F# is its smooth integration with the underlying .NET platform. New systems can be built using the function-first style, at the same time using existing libraries that have many years of development behind them.

F# has a well-deserved reputation as a great tool used to express complex algorithms, crunch numbers, and process all kinds of data. But as a general-purpose language, it also excels at everyday tasks like developing WPF GUI applications. It works best in code-oriented solutions with a thin functional adaptive layer over the traditional OOP API.

The most important message of this chapter is, “The type system is a developer’s best friend.” A types-first approach helps you design and write code that is intention-revealing (readable) and maintainable, and that has fewer defects. Understandably, many developers were disappointed by the type system in languages like C++, Java, and C#. So they turned to dynamically typed languages or convention-based approaches in statically typed languages. But the F# type system is a different game. Although it’s not ideal, it strikes a good balance between simplicity and power.

F# code that solves complex problems often looks deceptively simple because it’s standing on the shoulders of two giants: the type system and functional programming.

About the author

Dmitry Morozov is an experienced software developer, an F# enthusiast, and an active contributor to several F# OSS projects. He has been successfully using F# to build production applications since 2009. Currently Dmitry is a member of the engineering team at Tachyus, a company that creates technology to optimize energy production for the oil and gas industry.