async mvvm冻结了GUI

时间:2016-12-25 17:25:28

标签: asynchronous mvvm f#

我的目标是

  1. 启动GUI效果,
  2. 在不冻结GUI的情况下等待一些异步工作
  3. 做最终的GUI效果
  4. 我使用带有以下

    的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(为什么?)

1 个答案:

答案 0 :(得分:1)

问题在于您的CheckReport功能。虽然它是一个异步块,但它实际上从不调用任何异步工作(即:没有任何内容通过let!do!绑定),因此整个块同步运行。

即使工作在异步工作流内部,当您使用StartImmediate时,工作也会同步运行到第一个实际的异步函数调用,该调用将受let!或{{1 }}。由于您的工作是完全同步的,因此这会向上传播,最终会同步,阻止UI。

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

do!