namespace System
namespace System.Windows
namespace System.Windows.Forms
val E : e:IEvent<'c,'a> -> IEvent<'a> (requires delegate and 'c :> System.Delegate)

Full name: index.E
val e : IEvent<'c,'a> (requires delegate and 'c :> System.Delegate)
type IEvent<'T> = IEvent<Handler<'T>,'T>

Full name: Microsoft.FSharp.Control.IEvent<_>
val evt : Event<'a>
Multiple items
type Control =
  inherit Component
  new : unit -> Control + 4 overloads
  member AccessibilityObject : AccessibleObject
  member AccessibleDefaultActionDescription : string with get, set
  member AccessibleDescription : string with get, set
  member AccessibleName : string with get, set
  member AccessibleRole : AccessibleRole with get, set
  member AllowDrop : bool with get, set
  member Anchor : AnchorStyles with get, set
  member AutoScrollOffset : Point with get, set
  member AutoSize : bool with get, set
  ...
  nested type ControlAccessibleObject
  nested type ControlCollection

Full name: System.Windows.Forms.Control

--------------------
Control() : unit
Control(text: string) : unit
Control(parent: Control, text: string) : unit
Control(text: string, left: int, top: int, width: int, height: int) : unit
Control(parent: Control, text: string, left: int, top: int, width: int, height: int) : unit
Multiple items
module Event

from Microsoft.FSharp.Control

--------------------
type Event<'Delegate,'Args (requires delegate and 'Delegate :> Delegate)> =
  new : unit -> Event<'Delegate,'Args>
  member Trigger : sender:obj * args:'Args -> unit
  member Publish : IEvent<'Delegate,'Args>

Full name: Microsoft.FSharp.Control.Event<_,_>

--------------------
type Event<'T> =
  new : unit -> Event<'T>
  member Trigger : arg:'T -> unit
  member Publish : IEvent<'T>

Full name: Microsoft.FSharp.Control.Event<_>

--------------------
new : unit -> Event<'Delegate,'Args>

--------------------
new : unit -> Event<'T>
member System.IObservable.Add : callback:('T -> unit) -> unit
val e : 'a
member Event.Trigger : arg:'T -> unit
property Event.Publish: IEvent<'a>
val f : Form

Full name: index.f
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

Full name: System.Windows.Forms.Form

--------------------
Form() : unit
val md : IEvent<MouseEventArgs>

Full name: index.md
event Control.MouseDown: IEvent<MouseEventHandler,MouseEventArgs>
val net : obj

Full name: index.net
val printfn : format:Printf.TextWriterFormat<'T> -> 'T

Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.printfn
Control.Show() : unit
Form.Show(owner: IWin32Window) : unit
val orch : 'a

Full name: index.orch
val net : '_arg3

Full name: index.net
val net : '_arg3 (requires member ( ~+ ))

Full name: index.net
val net : 'a (requires member ( ~+ ) and member ( - ))

Full name: index.net
Multiple items
type MyForm =
  inherit Form
  new : unit -> MyForm

Full name: index.MyForm

--------------------
new : unit -> MyForm
val this : MyForm
type ControlStyles =
  | ContainerControl = 1
  | UserPaint = 2
  | Opaque = 4
  | ResizeRedraw = 16
  | FixedWidth = 32
  | FixedHeight = 64
  | StandardClick = 256
  | Selectable = 512
  | UserMouse = 1024
  | SupportsTransparentBackColor = 2048
  ...

Full name: System.Windows.Forms.ControlStyles
field ControlStyles.AllPaintingInWmPaint = 8192
field ControlStyles.OptimizedDoubleBuffer = 131072
val f : MyForm

Full name: index.f
val rect : 'a ref

Full name: index.rect
Multiple items
val ref : value:'T -> 'T ref

Full name: Microsoft.FSharp.Core.Operators.ref

--------------------
type 'T ref = Ref<'T>

Full name: Microsoft.FSharp.Core.ref<_>
val target : 'a ref

Full name: index.target
val bgcol : 'a ref

Full name: index.bgcol
val off : 'a ref

Full name: index.off
event Control.Paint: IEvent<PaintEventHandler,PaintEventArgs>
Control.Invalidate() : unit
Control.Invalidate(rc: System.Drawing.Rectangle) : unit
Control.Invalidate(invalidateChildren: bool) : unit
Control.Invalidate(region: System.Drawing.Region) : unit
Control.Invalidate(rc: System.Drawing.Rectangle, invalidateChildren: bool) : unit
Control.Invalidate(region: System.Drawing.Region, invalidateChildren: bool) : unit
val not : value:bool -> bool

Full name: Microsoft.FSharp.Core.Operators.not

What is evReact?

evReact is a vary compact and expressive library supporting reactive programming. Using evReact it is possible to track sequence of events and perform actions only when specific conditions are met. A set of operators allows the compositional definition of recognizers.

evReact has been developed in .NET using F# (it is available to .NET languages) and for Javascript using Typescript. More implementation will come in the future implementing the same model.

About this tutorial

  • In this tutorial you will learn the basics patterns to perform basic and avdanced tasks.
  • You can use F#, C# or Javascript

F# Tutorial

Playing with Windows Forms

In this section we will start using Windows Forms. The following code snippets are assumed sharing the following incipit:

1: 
2: 
3: 
4: 
5: 
6: 
7: 
8: 
9: 
open System.Windows.Forms
open EvReact
open EvReact.Expr
open EvReact.Orchestrator

let E (e:IEvent<'c,'a>) = 
  let evt = new Control.Event<'a>()
  e.Add(fun e -> evt.Trigger(e))
  evt.Publish

The E function is an adapter needed to convert the IEvent<'a, 'b> interface implemented by Windows Forms events into IEvent<'b> used by F#. Future versions of the library will not need this adapter anymore.

A simple example
1: 
2: 
3: 
4: 
5: 
6: 
7: 
8: 
let f = new Form(Text="Hello world from evReact")
let md = E f.MouseDown

let net = !!md |-> fun e -> printfn "Mouse down @(%d, %d)" e.X e.Y
f.Show()

let orch = Orchestrator.create()
Expr.start null orch net

A program using evReact needs an orchestrator to track the events defined by an expression (we will refer to the expression as net in this tutorial).

The first evReact expression

In this simple example we used the following expression:

1: 
let net = !!md |-> fun e -> printfn "Mouse down @(%d, %d)" e.X e.Y
  • Using the operator !! we create a simple listener of the mouse down events.
  • The operator |-> is used to associate an event handler to be fired when the net completes.

The net completes after the first click on the form.

The iteration operator
  • evReact expressions generate Petri nets where token flows when events are received.
  • A net can complete or terminate (i.e. all tokens are discarded)
  • The + prefix operator interates the network for ever, ensuring that whenever the net completes it is restarted
  • In our example we can refine the mouse down detection as follows:
1: 
  let net = +(!!md |-> fun e -> printfn "Mouse down @(%d, %d)" e.X e.Y)

Iteration completes each time its sub net completes, so the event handler associated with the operator |-> can be attached to md or to the iteration net.

Sequences
  • Sequence is used to state that a net should complete before another net can start
  • The infix operator for concatenating two nets is -
  • For instance the net for recognizing two mouse down is:
1: 
2: 
3: 
4: 
  let net = +(
                (!!md |-> fun e -> printfn "Mouse down 1 @(%d, %d)" e.X e.Y)
              - (!!md |-> fun e -> printfn "Mouse down 2 @(%d, %d)" e.X e.Y)
             )
Restriction
  • Iteration has no condition, so it is natural to wonder how it can be stopped
  • The infix restriction operator / allows indicating an array of events such that if an event occurs and it belongs to the array but it's not expected the net terminates (not just completes)
  • We can now track the whole drag and drop process:
1: 
2: 
3: 
4: 
5: 
6: 
  let net = 
    +(
        (!!md |-> fun e -> printfn "Mouse down @(%d,%d)" e.X e.Y) 
      - (+(!!mm) |-> fun e -> printfn "Mouse move @(%d,%d)" e.X e.Y) / [|mm; mu|]
      - !!mu |-> fun e -> printfn "Mouse up @(%d,%d)" e.X e.Y
    )
A new playground: the dragging square
  • In the next examples we will refer to the following form:
 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
14: 
15: 
16: 
17: 
  type MyForm() as this =
    inherit Form()
    do this.SetStyle(ControlStyles.AllPaintingInWmPaint 
                     ||| ControlStyles.OptimizedDoubleBuffer, true)

  let f = new MyForm(Text="Drag&Drop test with evReact", Width=640, Height=600)
  let rect = ref(new Rectangle(0, 0, 50, 50))
  let target = ref(new Rectangle(300, 300, 200, 200))
  let bgcol = ref(Brushes.Red)
  let off = ref(new Point())

  f.Paint.Add(fun e ->
    let g = e.Graphics
    g.DrawRectangle(Pens.Gray, !target)
    g.FillRectangle(!bgcol, !rect)
    g.DrawRectangle(Pens.Black, !rect)
  )
  • Using the global variables rect, target, bgcol, and off we can move the rectangle rect by just invalidating the form
Utilities
  • We will also use the following utility functions:
1: 
2: 
3: 
4: 
5: 
6: 
7: 
8: 
  // Utilities
  let uc col = bgcol := col; f.Invalidate()
  let dc col = !bgcol <> col
  let inR (p:Point) = (!rect).Contains(p)
  let placeR (p:Point) = 
    let r = !rect 
    rect := new Rectangle(p.X, p.Y, r.Width, r.Height);f.Invalidate()
  let inT () = (!target).Contains(!rect)
Hovering: conditional activation
  • Using the %- operation we can indicate a boolean predicate P that activates the node when the event is received only if P is satisfied
  • For example, we can define a net that takes care of highlighting the square when the mouse is over:
 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
  // Net recognizing hovering
  let highlight =
    +(
          ((mm %- fun e -> dc Brushes.Yellow && inR(e.Location)) 
           |-> fun _ -> uc Brushes.Yellow)
      ||| ((mm %- fun e -> dc Brushes.Red && not(inR(e.Location)))
           |-> fun _ -> uc Brushes.Red)
     )

  Expr.start null orch highlight
  • The ||| (any) operator allows us to run two nets in parallel, the resulting net completes whenever any of the branches completes (in this case are mutually exclusive given the condition)
Dragging the square
  • The last example of dragging will consist in implementing the dragging of the square
  • If the square is moved within the target square it will stay, otherwise it should be moved back to the origin
  • This is a complex behavior that can be defined in a very compact way using evReact as shown in the next page
Dragging the square: code
 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
14: 
15: 
16: 
17: 
18: 
19: 
  // Net performing the drag
  let drag = 
    +(
       ((md %- fun e -> (!rect).Contains(e.Location)) 
           |-> fun e -> 
                 let r = !rect
                 off := new Point(e.X - r.Left, e.Y - r.Top))
       - ((+(!!mm) |-> fun e -> 
                         placeR(new Point(e.X - (!off).X, e.Y - (!off).Y))
           ) / [| mm; mu |])
       - (!!mu |-> fun e -> 
                     if not(inT()) then
                       (placeR(new Point())
                       uc Brushes.Red))
     )

  let orch = Orchestrator.create()
  Expr.start null orch highlight
  Expr.start null orch drag
Dragging the square: considerations
  • The drag net simply uses all the operations we already discussed for implementing the operation
  • Note that we activate two nets on the orchestrator orch, so the highlight on hovering and the drag behaviors are tracked concurrently

C# Tutorial

Coming soon

Javascript Tutorial

Coming soon