我的目标是
>启动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