mvvm – 视图模型中的F#async / await
我在F#中的ViewModel
我正在尝试使用F#而不是C#来实现我的ViewModel. 所以,假设我有我的视图模型库实现(MVVM.ViewModel,它在C#中,但我可以从F#引用它)和一个简单的Status属性. namespace FuncViewModel open MVVM.ViewModel open System type MyFuncViewModel() = inherit ViewModelBase() let mutable status="" member this.RunSetStatus() = status <- "Reset @" + DateTime.Now.ToString "yy.MM.dd hh:mm:ss" base.OnPropertyChanged("Status") member this.SetStatus = new DelegateCommand(fun _ -> this.RunSetStatus() ) member this.Status with get() = status and set(value) = status <- value base.OnPropertyChanged(fun () -> this.Status) 一切都按预期工作,到目前为止一直很好(但是如果你发现任何概念上的错误,或者如果你发现上述代码有更惯用的版本,请告诉我) 介绍async / await模式 这就是我出错的地方:我知道如何在C#中做到这一点,但我在F#中并不擅长. 我试过以下内容. member this.RunSetStatus() = status <- "Start resetting @" + DateTime.Now.ToString "yy.MM.dd hh:mm:ss" base.OnPropertyChanged("Status") let task = async { do! Async.Sleep (30 * 1000) } Async.StartImmediate(task) status <- "Reset done @" + DateTime.Now.ToString "yy.MM.dd hh:mm:ss" base.OnPropertyChanged("Status") 问题是 – 当我运行完整的WPF应用程序时 – 我看不到预期的延迟:最终状态直接输出到输出. 如果我将上述Async.StartImmediate(任务)更改为Async.RunSynchronously(任务),当然我看到正在进行的延迟,但应用程序被冻结,所以这不是我想要的. 如果我将其重新排列为 member this.RunSetStatus() = status <- "Start resetting @" + DateTime.Now.ToString "yy.MM.dd hh:mm:ss" base.OnPropertyChanged("Status") let task = async { do! Async.Sleep (30 * 1000) status <- "Reset done @" + DateTime.Now.ToString "yy.MM.dd hh:mm:ss" base.OnPropertyChanged("Status") } Async.StartImmediate(task) 我收到一个错误
编辑(续) 最后,我也试过这个 member this.RunSetStatus() = status <- "Start resetting @" + DateTime.Now.ToString "yy.MM.dd hh:mm:ss" base.OnPropertyChanged("Status") let task = async { do! Async.Sleep (30 * 1000) } Async.StartWithContinuations(task,(fun _ -> this.Status <- "Reset done @" + DateTime.Now.ToString "yy.MM.dd hh:mm:ss"),(fun _ -> this.Status <- "Operation failed."),(fun _ -> this.Status <- "Operation canceled.")) 但应用程序崩溃时出现ArgumentException 堆栈跟踪
编辑2 – 发现问题 我不得不使用以下内容 – 更简单 – OnPropertyChanged的重载(它们都是按照这个source code实现并在C#中工作) member this.Status with get() = status and set(value) = status <- value base.OnPropertyChanged("Status") 解决方法
异常的原因是F#的函数不能表示为MemberExpression:
protected virtual void OnPropertyChanged<T>(Expression<Func<T>> selectorExpression) { if (selectorExpression == null) throw new ArgumentNullException("selectorExpression"); MemberExpression body = selectorExpression.Body as MemberExpression; if (body == null) throw new ArgumentException("The body must be a member expression"); OnPropertyChanged(body.Member.Name); } 在调试器中,您将看到实际获得的异常 – “正文必须是成员表达式”. 你的第一个代码: member this.RunSetStatus() = status <- "Reset @" + DateTime.Now.ToString "yy.MM.dd hh:mm:ss" base.OnPropertyChanged("Status") 因为您没有使用属性设置器状态,所以可以正常工作. 所以你需要使用不同的重载. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |