This problem has been driving me mad. Here's the general gist:
I have two projects in a solution: the first is an F# console application and the second is a C# library with a C#+XAML class called DisplayWindow
inheriting from the WPF Window. DisplayWindow
has a method public void SetMessage(string s) {...}
that makes the window display the text passed to it in big shiny letters that will probably also flash and spin arround and do everything else WPF is good at.
The problem is: From my F# program I need to make a function let openAWindow text = ???
so that it will open a new DisplayWindow
asynchronously every time its called with the 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/ that works but can sometimes (?) cause an ArgumentException with the error text "An entry with the same key already exists." so I have no idea whats going on there :(
I did this for our F# for Visualization library and then described the technique I used in my book Visual F# 2010 for Technical Computing.
Firstly, I wrote a lazy thunk that initializes WPF (including an STA UI thread and 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>
Then I wrote a spawn
function that dispatches the application of a function f
to an argument x
such that it is run on the UI thread:
> 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
Now it is just a case of invoking your openAWindow
function on the UI thread with:
let openAWindow text =
DisplayWindow().SetMessage text
spawn openAWindow text
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With