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
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
Javascript Tutorial
Coming soon