2012-01-14 63 views
3

這個問題一直讓我生氣。這裏的一般要點:F#異步顯示WPF窗口

我有一個解決方案中的兩個項目:第一個是F#控制檯應用程序,第二個是從C#+ XAML類繼承的名爲DisplayWindow的C#庫繼承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

我猜你有一個叫'Application.Run'主UI線程?如果是的話:如果你需要從其他線程訪問UI元素,就像這個答案中描述的那樣:http://stackoverflow.com/questions/1115132/stathread-as-async-workflow-in-f – wmeyer 2012-01-14 19:34:19

+0

@wmeyer是的,我看了看。我找不到Async.SwitchToGuiThread方法,但只有SwitchToContext,SwitchToNewThread和SwitchToThreadPool – 2012-01-15 11:41:57

+0

@Ciemnl SwitchToContext應該做的伎倆。你試過了嗎? – Joh 2012-01-17 16:08:10

回答

6

我這樣做是爲我們的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 
+1

感謝您的答案,它似乎在工作。我是一個noob,我真的不明白什麼派生正在做...我可以看到,它讓你通過它的函數在UI線程中運行,但是什麼原因讓'f _ ='和'(t:?> unit - >'b)()'? – 2012-01-15 12:11:37

+1

它忽略通過'Invoke'傳入的參數並返回一個函數而不是一個值。然後在當前線程上評估該函數,可以返回值或引發異常。 – 2012-01-15 12:54:32