FSharp.Control.Reactive


Introduction to Observables

Prerequisits

This page contains some basic examples of how to use Observable's. This is by no means a complete stable example and should only be used for demonstration purposes.

Subscribing on Observable

The following example show how the Enabling/Disabling of a button can be controled by looking at the input of another input field (TextBox).

Enable Disable Button

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
14: 
15: 
16: 
17: 
18: 
19: 
open System
open FSharp.Control.Reactive
open System.Windows.Forms


let buttonForm = new Form ()
let btn = new Button()
let txb = new TextBox()

txb.TextChanged
|> Observable.startWith [EventArgs.Empty]
|> Observable.subscribe (fun _ -> btn.Enabled <- not (String.IsNullOrEmpty txb.Text))

btn.Text <- "OK"
btn.Top <- 20

buttonForm.Controls.Add txb
buttonForm.Controls.Add btn
buttonForm.Show ()

Transforming Observable

Incoming emits can be transformed using the mapping functionality. Following example show how the input of a textbox can be transformed into the reversed value.

Reversed

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
14: 
15: 
module String = 
    let rev (s : string) = new String (s.ToCharArray () |> Array.rev)

let input = new TextBox()
let reversed = new Label()

input.TextChanged
|> Observable.map (fun _ -> input.Text |> String.rev)
|> Observable.subscribe (fun x -> reversed.Text <- x)

reversed.Top <- 20
let reverseForm = new Form ()
reverseForm.Controls.Add input
reverseForm.Controls.Add reversed
reverseForm.Show ()

Merging Two emits into one

Merging multiple events into one can be done with the Observable.merge primitive. Following example shows how we change the value of a label with the buttons ("Red" and "Green").

Red-Green

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
14: 
15: 
16: 
17: 
18: 
19: 
let redBtn = new Button()
let greenBtn = new Button()
let result = new Label()

let red = redBtn.Click |> Observable.mapTo "Red"
let green = greenBtn.Click |> Observable.mapTo "Green"

Observable.merge red green
|> Observable.subscribe (fun x -> result.Text <- x)

redBtn.Text <- "Red"
greenBtn.Text <- "Green"
greenBtn.Top <- 20
result.Left <- 100
let colorForm = new Form ()
colorForm.Controls.Add redBtn
colorForm.Controls.Add greenBtn
colorForm.Controls.Add result
colorForm.Show ()
namespace System
Multiple items
namespace FSharp

--------------------
namespace Microsoft.FSharp
Multiple items
namespace FSharp.Control

--------------------
namespace Microsoft.FSharp.Control
namespace FSharp.Control.Reactive
namespace System.Windows
namespace System.Windows.Forms
val buttonForm : Form
Multiple items
type Form =
  inherit ContainerControl
  new : unit -> Form
  member AcceptButton : IButtonControl with get, set
  member Activate : unit -> unit
  member ActiveMdiChild : Form
  member AddOwnedForm : ownedForm:Form -> unit
  member AllowTransparency : bool with get, set
  member AutoScale : bool with get, set
  member AutoScaleBaseSize : Size with get, set
  member AutoScroll : bool with get, set
  member AutoSize : bool with get, set
  ...
  nested type ControlCollection

--------------------
Form() : Form
val btn : Button
Multiple items
type Button =
  inherit ButtonBase
  new : unit -> Button
  member AutoSizeMode : AutoSizeMode with get, set
  member DialogResult : DialogResult with get, set
  member NotifyDefault : value:bool -> unit
  member PerformClick : unit -> unit
  member ToString : unit -> string
  event DoubleClick : EventHandler
  event MouseDoubleClick : MouseEventHandler

--------------------
Button() : Button
val txb : TextBox
Multiple items
type TextBox =
  inherit TextBoxBase
  new : unit -> TextBox
  member AcceptsReturn : bool with get, set
  member AutoCompleteCustomSource : AutoCompleteStringCollection with get, set
  member AutoCompleteMode : AutoCompleteMode with get, set
  member AutoCompleteSource : AutoCompleteSource with get, set
  member CharacterCasing : CharacterCasing with get, set
  member Multiline : bool with get, set
  member PasswordChar : char with get, set
  member Paste : text:string -> unit
  member ScrollBars : ScrollBars with get, set
  ...

--------------------
TextBox() : TextBox
event Control.TextChanged: IEvent<EventHandler,EventArgs>
Multiple items
module Observable

from FSharp.Control.Reactive

--------------------
module Observable

from Microsoft.FSharp.Control
val startWith : values:#seq<'T> -> source:IObservable<'T> -> IObservable<'T>
Multiple items
type EventArgs =
  new : unit -> EventArgs
  static val Empty : EventArgs

--------------------
EventArgs() : EventArgs
field EventArgs.Empty: EventArgs
Multiple items
val subscribe : onNext:('T -> unit) -> observable:IObservable<'T> -> IDisposable

--------------------
val subscribe : callback:('T -> unit) -> source:IObservable<'T> -> IDisposable
property Control.Enabled: bool
val not : value:bool -> bool
Multiple items
type String =
  new : value:char -> string + 7 overloads
  member Chars : int -> char
  member Clone : unit -> obj
  member CompareTo : value:obj -> int + 1 overload
  member Contains : value:string -> bool
  member CopyTo : sourceIndex:int * destination:char[] * destinationIndex:int * count:int -> unit
  member EndsWith : value:string -> bool + 2 overloads
  member Equals : obj:obj -> bool + 2 overloads
  member GetEnumerator : unit -> CharEnumerator
  member GetHashCode : unit -> int
  ...

--------------------
String(value: nativeptr<char>) : String
String(value: nativeptr<sbyte>) : String
String(value: char []) : String
String(c: char, count: int) : String
String(value: nativeptr<char>, startIndex: int, length: int) : String
String(value: nativeptr<sbyte>, startIndex: int, length: int) : String
String(value: char [], startIndex: int, length: int) : String
String(value: nativeptr<sbyte>, startIndex: int, length: int, enc: Text.Encoding) : String
String.IsNullOrEmpty(value: string) : bool
property TextBox.Text: string
property ButtonBase.Text: string
property Control.Top: int
property Control.Controls: Control.ControlCollection
Control.ControlCollection.Add(value: Control) : unit
Control.Show() : unit
Form.Show(owner: IWin32Window) : unit
val rev : s:string -> String
val s : string
Multiple items
val string : value:'T -> string

--------------------
type string = String
String.ToCharArray() : char []
String.ToCharArray(startIndex: int, length: int) : char []
type Array =
  member Clone : unit -> obj
  member CopyTo : array:Array * index:int -> unit + 1 overload
  member GetEnumerator : unit -> IEnumerator
  member GetLength : dimension:int -> int
  member GetLongLength : dimension:int -> int64
  member GetLowerBound : dimension:int -> int
  member GetUpperBound : dimension:int -> int
  member GetValue : [<ParamArray>] indices:int[] -> obj + 7 overloads
  member Initialize : unit -> unit
  member IsFixedSize : bool
  ...
val rev : array:'T [] -> 'T []
val input : TextBox
val reversed : Label
Multiple items
type Label =
  inherit Control
  new : unit -> Label
  member AutoEllipsis : bool with get, set
  member AutoSize : bool with get, set
  member BackgroundImage : Image with get, set
  member BackgroundImageLayout : ImageLayout with get, set
  member BorderStyle : BorderStyle with get, set
  member FlatStyle : FlatStyle with get, set
  member GetPreferredSize : proposedSize:Size -> Size
  member Image : Image with get, set
  member ImageAlign : ContentAlignment with get, set
  ...

--------------------
Label() : Label
Multiple items
val map : f:('a -> 'b) -> source:IObservable<'a> -> IObservable<'b>

--------------------
val map : mapping:('T -> 'U) -> source:IObservable<'T> -> IObservable<'U>
val x : String
property Label.Text: string
val reverseForm : Form
val redBtn : Button
val greenBtn : Button
val result : Label
val red : IObservable<string>
event Control.Click: IEvent<EventHandler,EventArgs>
val mapTo : x:'a -> source:IObservable<'T> -> IObservable<'a>
val green : IObservable<string>
Multiple items
val merge : second:IObservable<'T> -> first:IObservable<'T> -> IObservable<'T>

--------------------
val merge : source1:IObservable<'T> -> source2:IObservable<'T> -> IObservable<'T>
val x : string
property Control.Left: int
val colorForm : Form
Fork me on GitHub