2012-01-14 19 views
3

この問題は私を怒らせています。F#WPFウィンドウを非同期で表示する

ソリューションには2つのプロジェクトがあります:最初はF#コンソールアプリケーション、もう1つはC#+ XAMLクラスのDisplayWindowというWPFウィンドウを継承したC#ライブラリです。 DisplayWindowには、public void SetMessage(string s) {...}というメソッドがあります。このウィンドウには、ウィンドウにテキストが渡され、大きな光沢のある文字で表示されます。これは、おそらくフラッシュしてarroundを回転させ、WPFがうまくいくものです。

私のF#プログラムでは、という関数を作成して、テキストで呼び出されるたびに非同期的に新しいDisplayWindowを開くようにする必要があります。これを行う最善の方法は何ですか? async {}またはSystem.Threading.Threadを使用していますか?助けをありがとう:)

編集:私はこのブログの投稿http://deanchalk.com/2010/10/08/f-interacting-with-wpf-dispatcher-via-f-interactive-window/が動作しますが、時には(?)エラーテキスト "ArgumentExceptionの原因と同じキーを持つエントリが既に存在する"が見つかりました。私はまず、私は(を含むWPFを初期化怠惰なサンクを書きましたが起こっていただきました!見当がつかない:(

+0

?はいの場合:あなたは、他のスレッドからUI要素にアクセスする必要がこの回答で説明するようにそれを行う場合:http://stackoverflow.com/questions/1115132/stathread-as-async-workflow-in-f – wmeyer

+0

@wmeyerええ、私はそれを見ました。私はAsync.SwitchToGuiThreadメソッドを見つけることができませんでしたが、SwitchToContext、SwitchToNewThread、SwitchToThreadPoolだけです。 –

+0

@Ciemnl SwitchToContextはそのトリックを行うべきです。それを試しましたか? – Joh

答えて

6

私たちのF# for Visualizationライブラリのためにこれをやったし、私は私の本Visual F# 2010 for Technical Computingで使用される技術を説明した。

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> 

それから私は、引数それがUIスレッド上で実行されるようにxに機能fのアプリケーションをディスパッチspawn機能を書いた:

> 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機能を呼び出すだけの場合である:私はあなたが `Application.Run`呼び出すメインUIスレッドを持っていると思います

let openAWindow text = 
    DisplayWindow().SetMessage text 

spawn openAWindow text 
+1

それは働いていると思われる答えをありがとう。私はちょっと考えていますが、何が起こっているのかは分かりません... UIスレッドで関数を渡すことができますが、 'let f _ ='と '(t:?> unit - > 'b)()'のどちらかです。 –

+1

'Invoke'で渡された引数を無視し、値の代わりに関数を返します。その関数は現在のスレッドで評価され、値を返すか、例外を送出します。 –

関連する問題