2012-01-14 64 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