这个问题让我很生气。这是一般要点:
我在解决方案中有两个项目:第一个是F#控制台应用程序,第二个是C#库,其中包含一个名为DisplayWindow
的C#+ XAML类,继承自WPF窗口。 DisplayWindow
有一个方法public void SetMessage(string s) {...}
,它使窗口显示以大闪亮字母传递给它的文本,这些字母可能也会闪烁并旋转,并完成WPF擅长的所有其他操作。
问题是:从我的F#程序中我需要创建一个函数let openAWindow text = ???
,这样每次用文本调用时它都会异步打开一个新的DisplayWindow
。做这个的最好方式是什么?使用async {}
或System.Threading.Thread
?谢谢你的帮助:)
编辑:我发现此博客文章http://deanchalk.com/2010/10/08/f-interacting-with-wpf-dispatcher-via-f-interactive-window/有效,但有时(?)会导致带有错误文本的“ArgumentException”“已存在具有相同密钥的条目”。所以我不知道那里发生了什么:(
答案 0 :(得分:8)
我为我们的F# for Visualization库做了这个,然后描述了我在我的书Visual F# 2010 for Technical Computing中使用的技术。
首先,我写了一个懒惰的thunk,在强制评估时初始化WPF(包括STA UI线程和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
,使其在UI线程上运行:
> 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
现在只是在UI线程上调用openAWindow
函数的情况:
let openAWindow text =
DisplayWindow().SetMessage text
spawn openAWindow text