Async.fromBeginEnd与WinForms Begin / EndInvoke

时间:2015-06-25 15:21:05

标签: .net winforms asynchronous f#

我正在尝试在名为listControls的函数之上编写一个Async包装器,该函数从根控件开始提取Forms控件列表。计划是根据Control.BeginInvoke,Control.EndInvoke和Async.FromBeginEnd实现它

代码如下:

type private ListControls = delegate of unit -> Control list

let asyncListControls (root:Forms.Control) : Async<Control list> = 
    let beginInvoke (_, _) = 
        new ListControls(fun () -> listControls root)
        |> root.BeginInvoke

    let endInvoke result = 
        root.EndInvoke result :?> Control list

    Async.FromBeginEnd (beginInvoke, endInvoke)

我得到的行为是永远不会执行 endInvoke 。谁知道我做错了什么?有更好的方法吗?

修改

为了说清楚,最终使用Async.RunSynchronously执行此计算。

此外,如果我用

替换此代码
/// code below is reproduced from memory and might not compile
let asyncListControls (root:Forms.Control) : Async<Control list> =
     let ctx = WindowsFormsSynchronizationContext.Current
     async {
         do! Async.SwitchToContext ctx
         return listControls root
         do! Async.SwitchToThreadPool ()
     }

...然后它似乎工作,但我不喜欢它,因为强制上下文切换和异步计算应该在UI线程上构建的事实

2 个答案:

答案 0 :(得分:1)

AsyncTask不同,因为它不会在创作时开始。正如Daniel指出的那样,您必须使用Async或其他方法明确启动Async.RunSynchronously

答案 1 :(得分:0)

我对以下问题的不满:

在UI线程上使用Async.RunSynchronously执行异步操作,这会阻塞线程。

在执行期间,与Control.BeginInvoke一样,它将消息发送到UI线程。无法处理此消息,因为UI线程在Async.RunSynchron上被阻塞,从而导致死锁。