我的目标是
- 开始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
它的行为如预期的,所以我对上述内容感到满意。问题是当我用真正的阻止工作(例如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!
或do!
绑定什么),因此整个块都同步运行。
即使工作在异步工作流程内部,当您使用StartImmediate
时,该工作也同步运行到第一个实际的异步函数调用,该功能将受let!
或do!
绑定。由于您的工作是完全同步的,因此这会向上传播,最终是同步的,阻止了UI。
如果您的WCF绑定设置为包括任务返回的异步版本,则最好的方法是使用WCF方法的异步版本,看起来像:
let! resp = channel.CheckReportAsync(user) |> Async.AwaitTask