F # Display WPF window asynchronously

This problem drove me crazy. Here's the general meaning:

There are two projects in the solution: the first is the F # console application, and the second is the C # library with the C # + XAML class with the name DisplayWindowinheriting from the WPF window. DisplayWindowhas a method public void SetMessage(string s) {...}that causes the window to display text passed to it in large shiny letters, which are likely to also blink and rotate around and do whatever WPF can do.

The problem is this: from my F # program, I need to make a function let openAWindow text = ???so that it opens a new one DisplayWindowasynchronously every time it is called with text. What is the best way to do this? Using async {}or System.Threading.Thread? Thanks for the help:)

Edit: I found this blog post http://deanchalk.com/2010/10/08/f-interacting-with-wpf-dispatcher-via-f-interactive-window/ , which works, but sometimes (?) Causes ArgumentException with the error text "A record with the same key already exists." so I have no idea what is going on there :(

+5
source share
1 answer

I did this for our F # for Visualization , and then described the technique used in my book Visual F # 2010 for technical computing .

First, I wrote a lazy thunk that initializes WPF (including the STA and UI thread Application) when its evaluation is forced:

> let ui =
    let mk() =
      let wh = new ManualResetEvent(false)
      let application = ref null
      let start() =
        let app = Application()
        application := app
        ignore(wh.Set())
        app.Run() |> ignore
    let thread = Thread start
    thread.IsBackground <- true
    thread.SetApartmentState ApartmentState.STA
    thread.Start()
    ignore(wh.WaitOne())
    !application, thread
  lazy(mk());;
val ui : Lazy<Application * Thread> = <unevaluated>

spawn, f x , :

> let spawn : ('a -> 'b) -> 'a -> 'b =
    fun f x ->
      let app, thread = ui.Force()
      let f _ =
        try
          let f_x = f x
          fun () -> f_x
        with e ->
          fun () -> raise e
      let t = app.Dispatcher.Invoke(DispatcherPriority.Send, System.Func<_, _>(f), null)
      (t :?> unit -> 'b)();;
val spawn : ('a -> 'b) -> 'a -> 'b

openAWindow :

let openAWindow text =
  DisplayWindow().SetMessage text

spawn openAWindow text
+8

Source: https://habr.com/ru/post/1695732/


All Articles