1

I'm trying to run simple timer on project startup:

type NJHomeViewModel(config : Config) as X  =  
    inherit ViewModelBase()

    do
        (X.Timer : Timer).Elapsed.Add(fun args -> X.OnTimedEvent(args))
        (X.Timer : Timer).Interval  <- 3000.0
        (X.Timer : Timer).Enabled   <- true
        (X.Timer : Timer).Start()

    member X.Timer = new Timer()

    member X.OnTimedEvent args = X.Change()

So I want each 3 seconds run X.Change() function, it doesn't work this way, even when I added it to button nothing is changed.

member X.Next =
    new RelayCommand((fun canExecute -> true),
        (fun action -> 
            (X.Timer : Timer).Elapsed.Add(fun args -> X.OnTimedEvent(args))
            (X.Timer : Timer).Interval  <- 3000.0
            (X.Timer : Timer).Enabled   <- true
            (X.Timer : Timer).Start() ))

What is correct way to start my timer with a "Tick" action ?

Skomski
  • 4,827
  • 21
  • 30
cnd
  • 32,616
  • 62
  • 183
  • 313

3 Answers3

3

Consider an async loop in preference to using a timer; see e.g.

http://lorgonblog.wordpress.com/2010/03/27/f-async-on-the-client-side/

which has an example like

async {
    while true do
        do! Async.Sleep 1000
        textBox.Text <- System.DateTime.Now.ToString()
} |> Async.StartImmediate
Brian
  • 117,631
  • 17
  • 236
  • 300
2

member X.Timer = new Timer() This creates a property with a getter and when you access this property every time a new Timer is created.

To avoid this you can use a let binding as:

type NJHomeViewModel(config : Config) as X  =  
    inherit ViewModelBase()


    let timer = new Timer()
    do 
      timer.Elapsed.Add(fun args -> X.OnTimedEvent(args))
      timer.Interval  <- 3000.0
      timer.Enabled   <- true
      timer.Start()

    member X.Timer = timer

    member X.OnTimedEvent args = X.Change()
Ankur
  • 33,367
  • 2
  • 46
  • 72
1

You are using the server-based System.Timers.Timer which exposes an Elapsed event. There are other Timers available to you (e.g. the System.Threading.Timer where you can provide a callback method or the Windows.Forms.Timer where you can subscribe to the Tick event) so you need to pick the one most appropriate for your application and your use case. MSDN has an article about when to use which .NET Timer here

For the timer you are using, the Elapsed event will only run once if in a certain state. So that could be your problem. From MSDN

If Enabled is set to true and AutoReset is set to false, the Timer raises the Elapsed event only once, the first time the interval elapses.

The Threading timer would look something like

new Timer((fun _ -> YourMethod), null, 1000, 1000)

The Windows.Forms.Timer would look something like

formsTimer.Tick.Add( fun _ -> YourMethod())

In WPF you also have the DispatcherTimer available to you (more here). in F# this would look something like

let tmr = new DispatcherTimer(Interval = TimeSpan.FromSeconds(1.0))
tmr.Tick.Add( fun _ -> YourMethod())
tmr.Start()

There is a concise comparison of Forms.Timer and DispatcherTimer in another question on SO that might help you choose the right one for your app.

Community
  • 1
  • 1
Peter Kelly
  • 14,253
  • 6
  • 54
  • 63