F# asynchronous event handlers for WPF similar to C#'s async and await

后端 未结 2 2029
礼貌的吻别
礼貌的吻别 2021-01-05 13:05

How does one code an asynchronous WPF (or Windows Forms) event handler in F#? Specifically, is there any coding pattern that approximates C# 5\'s async and await?

He

2条回答
  •  情书的邮戳
    2021-01-05 13:20

    The first step is to make incrementSlowly asynchronous. This is actually synchronous in your C# code, which is probably not a good idea - in a realistic scenario, this could be communicating with network, so very often this can actually be asynchronous:

    let incrementSlowly previous = async {
      do! Async.Sleep(3000)
      if previous = 2 then failwith "Oops!"
      return previous + 1 }
    

    Now, you can make the button click handler also asynchronous. We'll start it using Async.StartImmediate later to make sure that we can access UI elements, so we do not have to worry about dispatechers or UI threads for now:

    let btn_Click (sender : obj) e = async {
      let btn = sender :?> Button
      btn.IsEnabled <- false
      try 
        try 
          let prev = btn.Content :?> int
          let! next = incrementSlowly prev
          btn.Content <- next
        with ex -> btn.Content <- ex.Message
      finally
        btn.IsEnabled <- true }
    

    The final step is to change the event registration. Something like this should do the trick:

    btn.Click.Add(RoutedEventHandler(fun sender e ->
      btn_Click sender e |> Async.StartImmediate)
    

    The key thing is Async.StartImmediate which starts the asynchronous workflow. When we call this on the UI thread, it ensures that all the actual work is done on the UI thread (unless you offload it explicitly to background) and so it is safe to access UI elements in your code.

提交回复
热议问题