异步 – 异步mvvm冻结GUI

我的目标是

>启动GUI效果,
>等待一些异步工作而不冻结GUI
>做最后的GUI效果

我已经使用具有以下内容的viewmodel准备了第一个演示代码

member this.RunSetStatus() = 
    async {
            this.Status <- "!Start resetting @" + DateTime.Now.ToString "yy.MM.dd hh:mm:ss"
            let! task = async {

                do! Async.Sleep (10 * 1000) 
                return "!Reset done @" + DateTime.Now.ToString "yy.MM.dd hh:mm:ss"
            }

            this.Status <- task
        } |> Async.StartImmediate

它表现得如预期,所以我对上述情况感到满意.
问题是我在演示中使用真正的阻塞工作替换Sleep,就像wcf使用者一样,检索一些结果.

member this.CheckReport(user : string) =
    async {
        let endpoint = new ServiceEndpoint(ContractDescription.GetContract(typeof<IClaimService>),
                        new BasicHttpBinding(),
                        new EndpointAddress(address))
        let factory = new ChannelFactory<IClaimService>(endpoint)
        let channel = factory.CreateChannel()
        let resp = channel.CheckReport(user) 
        factory.Close()
        return resp
    }

从我的最终委托命令调用

let RefreshLogic() = 
    this.RefreshIsActive <- true
    async {
        let cons = ConsumerLib.ConsumerWCF() 
        let! task, msg = async {
            try
                let! resp = cons.CheckReport(Environment.UserName.ToLower()) 
                return resp , "" 
            with 
            |exc -> return [||], (ConsumerLib.FindInner(exc).Message + ConsumerLib.FindInner(exc).StackTrace)
            }
        this.Reports <- task
        this.RefreshIsActive <- false
        this.StatusMsg <- msg
        this.ExportCommand.RaiseCanExecuteChanged() 
        } |> Async.StartImmediate

不幸的是,它在刷新时冻结了GUI(为什么?)

最佳答案 问题是你的CheckReport功能.虽然它是一个异步块,它实际上从不调用任何异步工作(即:没有任何东西通过let!或者!!),所以整个块同步运行.

即使工作在异步工作流内部,当您使用StartImmediate时,工作也会同步运行到第一个实际的异步函数调用,这将被let绑定!还是做!由于您的工作是完全同步的,因此这会向上传播,最终会同步,阻止UI.

如果你的WCF绑定被设置为包含Task返回的异步版本,那么这里最好的方法是使用WCF方法的异步版本,它看起来像:

let! resp = channel.CheckReportAsync(user) |> Async.AwaitTask
点赞