Я сделал это для нашей библиотеки F # для визуализации , а затем описал метод, который использовал в своей книге Visual F # 2010 для технических вычислений .
Во-первых, янаписал ленивый thunk, который инициализирует WPF (включая поток пользовательского интерфейса STA и Application
), когда его оценка принудительно:
> 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